Search code examples
gcclinkerstatic-linkingdynamic-linking

segfault after linking static library into both exe and shared lib


I have a program that statically links glib library and dynamically links a shared library that in turn also statically links the same glib library. When I run the program I get a segfault. After debugging in gdb I found that there is a global static variable defined in glib that's being set and it had different values in one call trace and than a later call trace. I then noticed that the variable addresses were different as well. So it seems like there are two copies of the global static variable? Shouldn't the executable override the symbol from shared library so there is only one global static variable in the executable during dynamic linking?

The other part of the story is that there is another executable that does the same as above, which seems to behave okay i.e., no segfault (haven't debugged to see if the different code paths load the same static variable). So perhaps this behavior is not deterministic. The following issue is happening with gcc (8.3.1) on Linux (centos 7).

executableA (segfault)                          executableB (no segfault)
|            \                                     |        \
| (static)    \(shared)                            |(static) \(shared)
|              \                                   |          \
libglib-2.0.a   libA.so                        libglib-2.0.a   libA.so
                 |                                               |
                 | (static)                                      |(static)
                 |                                               |
              libglib-2.0.a                                  libglib-2.0.a

Solution

  • So it seems like there are two copies of the global static variable?

    Yes, that is expected.

    Shouldn't the executable override the symbol from shared library so there is only one global static variable in the executable during dynamic linking?

    A static variable by definition has local linkage -- it is not accessible from any other compilation unit, and is not exported from the shared library(ies).

    You would have to make this variable (and any other similar variables) non-static and exported from both shared libraries. Only then will the dynamic loader bind all references to this variable to a single instance.

    Note that linking separate copies of libglib-2.0.a into shared libraries without controlling symbol visibility is asking for trouble. Whatever you hoped to achieve by doing that, you are not achieving.

    there is another executable that does the same as above, which seems to behave okay

    Ah, programming by coincidence. The mine you stepped on didn't explode, so it should be ok to continue doing that.