Shared Library Exceptions & Vague Linkage

Discussion in 'C++' started by akennis, Jul 25, 2006.

  1. akennis

    akennis Guest

    First of all, sorry for duplicating this post. I put it up in the
    alt.comp.lang.learn.c-c++ mistakenly.

    I'm investigating a problem whereby exceptions thrown from functions in
    a Shared Library which was dynamically loaded (dlopen) are not properly
    caught by the caller. Specifically, when compiling with G++ version
    4.0, the RTTI data associated with the exception types is not being
    properly aligned between the Shared Library and its caller.

    The online manual for GCC describes this as a problem due to its
    implementation of Vague Linkage, but does not fully explain how the
    problem can be resolved.

    I've been able to resolve the problem by taking the typeid of the
    exception type before entering the try/catch block in the driver. This
    is illustrated in the following code:

    // DynamicLink.h
    // **************

    #ifndef dynamiclink_h
    #define dynamiclink_h

    #include <typeinfo>

    namespace DynamicLink
    {
    I'm investigating a problem whereby exceptions thrown from functions in
    a Shared Library which was dynamically loaded (dlopen) are not properly
    caught by the caller. Specifically, when compiling with G++ version
    4.0, the RTTI data associated with the exception types is not being
    properly aligned between the Shared Library and its caller.

    The online manual for GCC describes this as a problem due to its
    implementation of Vague Linkage, but does not fully explain how the
    problem can be resolved.

    I've been able to resolve the problem by taking the typeid of the
    exception type before entering the try/catch block in the driver. This
    is illustrated in the following code:

    // DynamicLink.h
    // **************

    #ifndef dynamiclink_h
    #define dynamiclink_h

    #include <typeinfo>

    namespace DynamicLink
    {

    enum ExceptionType1
    {
    a = 0,
    b = 1

    };

    extern "C" void throwExceptionType1();
    typedef void (* throwExceptionType1_Fn)();

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI();
    typedef void (* dumpRTTI_Fn)();

    char const * ExceptionType1__TypeId =
    typeid(DynamicLink::ExceptionType1).name();

    #endif

    }

    #endif

    // DynamicLink.cpp
    // ***************

    // build: g++ -DFIX_VAGUE_LINKAGE -g -shared -o libDynamicLink.so
    DynamicLink.cpp

    #include "DynamicLink.h"

    #include <stdio.h>

    namespace DynamicLink
    {

    extern "C" void throwExceptionType1()
    {
    throw a;

    }

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI()
    {
    printf("Shared Library side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    }

    #endif

    }

    // Driver.cpp
    // *********

    // build: g++ -DFIX_VAGUE_LINKAGE -g -fpic -o DynamicLinkDriver -ldl
    Driver.cpp

    #include "DynamicLink.h"
    using namespace DynamicLink;

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

    int main(int argv, char const * * arc)
    {
    void * lib = dlopen("./libDynamicLink.so", RTLD_NOW | RTLD_GLOBAL);

    #ifdef FIX_VAGUE_LINKAGE

    dumpRTTI_Fn dumpRTTI_fn = (dumpRTTI_Fn) dlsym(lib, "dumpRTTI");
    dumpRTTI_fn();
    printf("Driver side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    #endif

    try
    {
    throwExceptionType1_Fn throwExceptionType1_fn =
    (throwExceptionType1_Fn) dlsym(lib, "throwExceptionType1");
    throwExceptionType1_fn();
    }
    catch (ExceptionType1 & e)
    {
    printf("caught ExceptionType1: %s %u - %u\n", __FILE__, __LINE__,
    (int) e);
    }
    catch (...)
    {
    printf("caught unknown exception: %s %u\n", __FILE__, __LINE__);
    }

    dlclose(lib);

    return 0;

    }

    // END CODE

    If you compile the Shared Library and its associated executable driver
    using the g++ commands given, then the proper exception handlers will
    be executed. If you remove the -DFIX_VAGUE_LINKAGE directive from the
    compile commands, then the catch (...) handler is erroniously executed.

    The trick is putting the typeid(...) calls in the common header file.
    Somehow this seems to resolve the typeid misalignment.

    I would like to understand why this method is solving the problem, and
    also if there is a better way to go about doing this. I suspect that
    there is some combination of compiler / linker commands which can be
    used, but I've yet to figure out which ones.

    Thank you,

    Albert Kennis
    enum ExceptionType1
    {
    a = 0,
    b = 1

    };

    extern "C" void throwExceptionType1();
    typedef void (* throwExceptionType1_Fn)();

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI();
    typedef void (* dumpRTTI_Fn)();

    char const * ExceptionType1__TypeId =
    typeid(DynamicLink::ExceptionType1).name();

    #endif

    }

    #endif

    // DynamicLink.cpp
    // ***************

    // build: g++ -DFIX_VAGUE_LINKAGE -g -shared -o libDynamicLink.so
    DynamicLink.cpp

    #include "DynamicLink.h"

    #include <stdio.h>

    namespace DynamicLink
    {

    extern "C" void throwExceptionType1()
    {
    throw a;

    }

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI()
    {
    printf("Shared Library side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    }

    #endif

    }

    // Driver.cpp
    // *********

    // build: g++ -DFIX_VAGUE_LINKAGE -g -fpic -o DynamicLinkDriver -ldl
    Driver.cpp

    #include "DynamicLink.h"
    using namespace DynamicLink;

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

    int main(int argv, char const * * arc)
    {
    void * lib = dlopen("./libDynamicLink.so", RTLD_NOW | RTLD_GLOBAL);

    #ifdef FIX_VAGUE_LINKAGE

    dumpRTTI_Fn dumpRTTI_fn = (dumpRTTI_Fn) dlsym(lib, "dumpRTTI");
    dumpRTTI_fn();
    printf("Driver side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    #endif

    try
    {
    throwExceptionType1_Fn throwExceptionType1_fn =
    (throwExceptionType1_Fn) dlsym(lib, "throwExceptionType1");
    throwExceptionType1_fn();
    }
    catch (ExceptionType1 & e)
    {
    printf("caught ExceptionType1: %s %u - %u\n", __FILE__, __LINE__,
    (int) e);
    }
    catch (...)
    {
    printf("caught unknown exception: %s %u\n", __FILE__, __LINE__);
    }

    dlclose(lib);

    return 0;

    }

    // END CODE

    If you compile the Shared Library and its associated executable driver
    using the g++ commands given, then the proper exception handlers will
    be executed. If you remove the -DFIX_VAGUE_LINKAGE directive from the
    compile commands, then the catch (...) handler is erroniously executed.

    The trick is putting the typeid(...) calls in the common header file.
    Somehow this seems to resolve the typeid misalignment.

    I would like to understand why this method is solving the problem, and
    also if there is a better way to go about doing this. I suspect that
    there is some combination of compiler / linker commands which can be
    used, but I've yet to figure out which ones.

    Thank you,

    Albert Kennis
    akennis, Jul 25, 2006
    #1
    1. Advertising

  2. akennis

    akennis Guest

    I mixed up the message text - sorry again:

    I'm investigating a problem whereby exceptions thrown from functions in
    a Shared Library which was dynamically loaded (dlopen) are not properly
    caught by the caller. Specifically, when compiling with G++ version
    4.0, the RTTI data associated with the exception types is not being
    properly aligned between the Shared Library and its caller.

    The online manual for GCC describes this as a problem due to its
    implementation of Vague Linkage, but does not fully explain how the
    problem can be resolved.

    I've been able to resolve the problem by taking the typeid of the
    exception type before entering the try/catch block in the driver. This
    is illustrated in the following code:

    // DynamicLink.h
    // **************

    #ifndef dynamiclink_h
    #define dynamiclink_h

    #include <typeinfo>

    namespace DynamicLink
    {

    enum ExceptionType1
    {
    a = 0,
    b = 1

    };

    extern "C" void throwExceptionType1();
    typedef void (* throwExceptionType1_Fn)();

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI();
    typedef void (* dumpRTTI_Fn)();

    char const * ExceptionType1__TypeId =
    typeid(DynamicLink::ExceptionType1).name();

    #endif

    }

    #endif

    // DynamicLink.cpp
    // ***************

    // build: g++ -DFIX_VAGUE_LINKAGE -g -shared -o libDynamicLink.so
    DynamicLink.cpp

    #include "DynamicLink.h"

    #include <stdio.h>

    namespace DynamicLink
    {

    extern "C" void throwExceptionType1()
    {
    throw a;

    }

    #ifdef FIX_VAGUE_LINKAGE

    extern "C" void dumpRTTI()
    {
    printf("Shared Library side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    }

    #endif

    }

    // Driver.cpp
    // *********

    // build: g++ -DFIX_VAGUE_LINKAGE -g -fpic -o DynamicLinkDriver -ldl
    Driver.cpp

    #include "DynamicLink.h"
    using namespace DynamicLink;

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

    int main(int argv, char const * * arc)
    {
    void * lib = dlopen("./libDynamicLink.so", RTLD_NOW | RTLD_GLOBAL);

    #ifdef FIX_VAGUE_LINKAGE

    dumpRTTI_Fn dumpRTTI_fn = (dumpRTTI_Fn) dlsym(lib, "dumpRTTI");
    dumpRTTI_fn();
    printf("Driver side RTTI:\n");
    printf("typeid(ExceptionType1): %s %p\n", ExceptionType1__TypeId,
    ExceptionType1__TypeId);

    #endif

    try
    {
    throwExceptionType1_Fn throwExceptionType1_fn =
    (throwExceptionType1_Fn) dlsym(lib, "throwExceptionType1");
    throwExceptionType1_fn();
    }
    catch (ExceptionType1 & e)
    {
    printf("caught ExceptionType1: %s %u - %u\n", __FILE__, __LINE__,
    (int) e);
    }
    catch (...)
    {
    printf("caught unknown exception: %s %u\n", __FILE__, __LINE__);
    }

    dlclose(lib);

    return 0;

    }

    // END CODE

    If you compile the Shared Library and its associated executable driver
    using the g++ commands given, then the proper exception handlers will
    be executed. If you remove the -DFIX_VAGUE_LINKAGE directive from the
    compile commands, then the catch (...) handler is erroniously executed.

    The trick is putting the typeid(...) calls in the common header file.
    Somehow this seems to resolve the typeid misalignment.

    I would like to understand why this method is solving the problem, and
    also if there is a better way to go about doing this. I suspect that
    there is some combination of compiler / linker commands which can be
    used, but I've yet to figure out which ones.

    Thank you,

    Albert Kennis
    akennis, Jul 25, 2006
    #2
    1. Advertising

  3. akennis

    Jack Klein Guest

    On 24 Jul 2006 19:23:05 -0700, "akennis" <> wrote in
    comp.lang.c++:

    > First of all, sorry for duplicating this post. I put it up in the
    > alt.comp.lang.learn.c-c++ mistakenly.
    >
    > I'm investigating a problem whereby exceptions thrown from functions in
    > a Shared Library which was dynamically loaded (dlopen) are not properly
    > caught by the caller. Specifically, when compiling with G++ version
    > 4.0, the RTTI data associated with the exception types is not being
    > properly aligned between the Shared Library and its caller.


    [snip]

    You're still in the wrong place. C++ does not have or define shared
    libraries, dynamic loading, or dlopen().

    news:comp.os.linux.development.apps

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Jul 25, 2006
    #3
  4. akennis

    Peter Guest

    akennis wrote:
    > First of all, sorry for duplicating this post. I put it up in the
    > alt.comp.lang.learn.c-c++ mistakenly.
    >
    > I'm investigating a problem whereby exceptions thrown from functions in
    > a Shared Library which was dynamically loaded (dlopen) are not properly
    > caught by the caller. Specifically, when compiling with G++ version
    > 4.0, the RTTI data associated with the exception types is not being
    > properly aligned between the Shared Library and its caller.



    make certain that you have only one definition of the matching symbols
    in all of your exceutable and shared libraries.
    I guess this is being caused by having multiple copies of the matching
    code inside the excecutable and again inside the shared library
    Peter, Jul 25, 2006
    #4
  5. akennis

    akennis Guest

    Peter wrote:

    > make certain that you have only one definition of the matching symbols
    > in all of your exceutable and shared libraries.
    > I guess this is being caused by having multiple copies of the matching
    > code inside the excecutable and again inside the shared library


    If the -DFIX_VAGUE_LINKAGE command is removed, then the only code
    common between the shared library and the executable are the type &
    function declarations in the header file. These are required inorder
    to establish the shared library API.

    I think that the type_info objects are being compiled into the binaries
    automatically, and so these ARE present in both. How can I prevent the
    type_info stuff from being compiled into the executable?

    Thanks.
    akennis, Jul 26, 2006
    #5
  6. akennis

    Peter Guest

    akennis wrote:
    > void * lib = dlopen("./libDynamicLink.so", RTLD_NOW | RTLD_GLOBAL);
    > ....
    > dlclose(lib);



    dlopen belongs into a constructor and dlclose into the matching
    destructor.
    If dlopen fails throw an exception containing the error information.
    Peter, Jul 26, 2006
    #6
  7. akennis

    Peter Guest

    akennis wrote:

    > try
    > {
    > throwExceptionType1_Fn throwExceptionType1_fn =
    > (throwExceptionType1_Fn) dlsym(lib, "throwExceptionType1");
    > throwExceptionType1_fn();
    > }
    > catch (ExceptionType1 & e)



    it is unlikely that you want to modify the exception inside the catch
    block.
    Thus catch a const reference of this type.
    Peter, Jul 26, 2006
    #7
  8. akennis

    Peter Guest

    akennis wrote:
    > I mixed up the message text - sorry again:
    >



    I did not know that it is possible to get the typeid for an
    enumeration.
    Try again with a class which has at least one virtual function
    -- e.g. derived from the standard exception class.

    And also -- the call to dlsym() belongs into a C++ wrapper which checks
    for success and throws an exception otherwise.
    The assumption being that you write such a wrapper only once and reuse
    it.
    And another assumption being that at the place where you call dlopen()
    you don't want to deal with the possibility that it may fail,
    but you want to delegate this task to some piece of code up the stack.
    Peter, Jul 26, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VisionSet
    Replies:
    4
    Views:
    372
    John C. Bollinger
    Dec 6, 2004
  2. Chad

    vague lvalue vs rvalue question

    Chad, Apr 16, 2008, in forum: C Programming
    Replies:
    0
    Views:
    254
  3. Replies:
    1
    Views:
    590
    Michael DOUBEZ
    Sep 12, 2008
  4. Bill Youngman
    Replies:
    1
    Views:
    188
    Bill Youngman
    Oct 11, 2005
  5. bil050
    Replies:
    0
    Views:
    412
    bil050
    Apr 20, 2012
Loading...

Share This Page