読者です 読者をやめる 読者になる 読者になる

libdl.soをg++でリンクすると妙なことが起こる

debian lenny@amd64で、dlopenするコードを実行するとvalgrindで5 errorsと出る。特におかしなことしてないはずなんだけど。自分はバイナリアンではないので現象が分かってないんだけど。

$ g++ -rdynamic -g -o foo foo.c -ldl
$ valgrind ./foo

これで

[kuenishi@] $ valgrind ./foo
==19273== Memcheck, a memory error detector.
==19273== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==19273== Using LibVEX rev 1804, a library for dynamic binary translation.
==19273== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==19273== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
==19273== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==19273== For more details, rerun with: -v
==19273==

  • 0.416147

==19273==
==19273== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 8 from 1)
==19273== malloc/free: in use at exit: 56 bytes in 1 blocks.
==19273== malloc/free: 3 allocs, 2 frees, 105 bytes allocated.
==19273== For counts of detected errors, rerun with: -v
==19273== searching for pointers to 1 not-freed blocks.
==19273== checked 190,232 bytes.
==19273==
==19273== LEAK SUMMARY:
==19273== definitely lost: 0 bytes in 0 blocks.
==19273== possibly lost: 0 bytes in 0 blocks.
==19273== still reachable: 56 bytes in 1 blocks.
==19273== suppressed: 0 bytes in 0 blocks.
==19273== Rerun with --leak-check=full to see details of leaked memory.
[kuenishi@] $

こんな風になる。ちなみにgccでコンパイルするとこんなことにはならない。コードはmanからもってきた。

       #include <stdio.h>
       #include <stdlib.h>
       #include <dlfcn.h>

       int
       main(int argc, char **argv)
       {
           void *handle;
           double (*cosine)(double);
           char *error;

           handle = dlopen("libm.so", RTLD_LAZY);
           if (!handle) {
               fprintf(stderr, "%s\n", dlerror());
               exit(EXIT_FAILURE);
           }

           dlerror();    /* Clear any existing error */

           /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
              would seem more natural, but the C99 standard leaves
              casting from "void *" to a function pointer undefined.
              The assignment used below is the POSIX.1-2003 (Technical
              Corrigendum 1) workaround; see the Rationale for the
              POSIX specification of dlsym(). */

           *(void **) (&cosine) = dlsym(handle, "cos");

           if ((error = dlerror()) != NULL)  {
               fprintf(stderr, "%s\n", error);
               exit(EXIT_FAILURE);
           }

           printf("%f\n", (*cosine)(2.0));
           dlclose(handle);
           exit(EXIT_SUCCESS);
       }

valgrindに-vつけるとこんなのが出る。

    • 19279-- Contents of /proc/version:
    • 19279-- Linux version 2.6.24-1-amd64 (Debian 2.6.24-6) (waldi@debian.org) (gcc version 4.1.3 20080308 (prerelease) (Debian 4.1.2-21)) #1 SMP Fri Apr 18 23:08:22 UTC 2008
    • 19279-- Arch and hwcaps: AMD64, amd64-sse2