tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/39986: libmapper_zone.so is trying to call undefined weak symbol



hi, all

> While running mail/sylpheed it exits with the following line on my terminal 
> at random occasions (when opening mail):
>
> /usr/lib/i18n/libmapper_zone.so.4.4: Trying to call undefined weak symbol 
> `__deregister_frame_info'
>

this is not mapper_zone(which is part of Citrus iconv)'s problem.
i suspect C/C++ runtime problem on NetBSD.

[background]

  GTK+2 have so called gtkimmodule, own input method framework
  that doesn't depend on X Window System's XIM protocol.
  it isn't apply server/client style remote procedule call,
  simply and directly depends on dlopen(3).
  and some 3rd party gtkimmodule(AFAIK pkgsrc-wip/scim) is C++ ABI.

  but NetBSD's dlopen(3), dynamic loading C++ shared library from C application
 may causes crash.

[reproduce the problem]

  1. build C++ shared library

    $ cat >foo.h
    #if defined(__cplusplus)
    extern "C" {
    #endif
    void foo(void);
    #if defined(__cplusplus)
    }
    #endif
    ^D
    $ cat >foo.cpp
    #include <string>
    #include <iostream>
    #include "foo.h"

    void
    foo(void)
    {
        std::basic_string<char> msg;
        msg = std::basic_string<char>("hello, C++ world.\n");
        std::cout << msg;
    }
    ^D
    $ g++ -shared -g -o libfoo.so foo.cpp
    $ cat >bar.h
    void bar(void);
    ^D

  2. build C shared library.

    $ cat >bar.c
    #include <stdio.h>
    #include "bar.h"

    void
    bar(void)
    {
        printf("hello, C world.\n");
    }
    ^D
    $ gcc -shared -g -o libbar.so bar.c

  3. build application that dlopen(3)  both C/C++ libraries.

    $ cat >buzz.c
    #include <dlfcn.h>

    typedef void (*func_t)(void);
    int
    main(void)
    {
        void *foo, *foo_func, *bar, *bar_func;

        foo = dlopen("libfoo.so", RTLD_GLOBAL);
        foo_func = dlsym(foo, "foo");
        ((func_t)foo_func)();

        bar = dlopen("libbar.so", RTLD_GLOBAL);
        bar_func = dlsym(bar, "bar");
        ((func_t)bar_func)();

        dlclose(foo);
        dlclose(bar);

        return 0;
    }
    ^D
    $ gcc -g -o buzz buzz.c

  4. run it.

    $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./buzz
    hello, C++ world.
    hello, C world.
    ./libbar.so: Trying to call undefined weak symbol `__deregister_frame_info'

  this problem happen only following order:
    dlclose(foo)        /* C++ library */
    dlclose(bar)        /* C library */

  following order no harm:
    dlclose(bar)        /* C library */
    dlclose(foo)        /* C++ library */

[why this problem occur?]

  C++ throws exception via stack frame by __(de)register_frame_info().
  this function exists in libgcc_s.so:

    $ nm /usr/lib/libgcc_s.so | egrep "__(de)?register_frame_info$"
    00007e00 T __deregister_frame_info
    00007c60 T __register_frame_info

  and crtbeginS.o has weak reference for it;

    $ nm /usr/lib/crtbeginS.o  | egrep "__(de)?register_frame_info$"
             w __deregister_frame_info
             w __register_frame_info

  so that both C++ and C library refer it too:

    $ nm libfoo.so | egrep "__(de)?register_frame_info"
             w __deregister_frame_info@@GCC_3.0
             w __register_frame_info@@GCC_3.0

    $ nm libbar.so | egrep "__(de)?register_frame_info"
             w __deregister_frame_info
             w __register_frame_info

  but, dependency for libgcc_s.so is recoreded only C++ library.

    $ ldd libfoo.so
    libfoo.so:
            -lc.12 => /usr/lib/libc.so.12
            -lstdc++.7 => /usr/lib/libstdc++.so.7
            -lm.0 => /usr/lib/libm.so.0
            -lgcc_s.1 => /usr/lib/libgcc_s.so.1

    libbar.so:
            -lc.12 => /usr/lib/libc.so.12

  so if dlclose(3) libfoo before libbar, can't resolve real
  __deregistered_frame_info() because libgcc_s has been unloaded.
  (if only load/unload C library, __deregister_frame_info is fake
symbol, no problem)

    $ LD_DEBUG=1 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./buzz
    ...
    _rtld_call_fini_functions(0)
    _rtld_initlist_tsort
    calling fini function ./libfoo.so at 0xbbadd900
    calling fini function /usr/lib/libgcc_s.so.1 at 0xbb9de140
    calling fini function /usr/lib/libm.so.0 at 0xbb9f6880
    calling fini function /usr/lib/libstdc++.so.7 at 0xbbab2ce0
    _rtld_call_fini_functions(0)
    _rtld_initlist_tsort
    calling fini function ./libbar.so at 0xbb9d4430
    ./libbar.so: Trying to call undefined weak symbol `__deregister_frame_info'
    rtld_exit()
    _rtld_call_fini_functions(1)
    _rtld_initlist_tsort
    calling fini function /usr/lib/libc.so.12 at 0xbbbc51e0 (DF_1_INITFIRST)

[how to fix]

  i'm not toolchain and elf guru, so i can't decided my mind:

  1. don't use __(de)?register_frame_info but .eh_frame section instead
    by adding --eh-frame-hdr option.  it seems that Linux/glibc2 now using it,
    also FreeBSD, OpenBSD too

    $ /usr/pkg/emul/linux/usr/bin/gcc -### -shared -o libbar.so bar.c
    ... "--eh-frame-hdr" ...

  2. clarify application using dlopen(3) must add -lgcc_s option.

    same approach of non ptheaded application loading ptheaded library.
    see following discussion:
    http://mail-index.netbsd.org/pkgsrc-users/2009/01/17/msg009088.html

  3. hack ld.elf_so
    re-add fake symbol to undefined weak symbol.
    ummmm, i think bad idea.


any idea?

very truly yours.
-- 
Takehiko NOZAKI <tnozaki%NetBSD.org@localhost>


Home | Main Index | Thread Index | Old Index