Question

I've probably encountered a bug in GCC or linker that happens when there's a global variable named 'error' in a shared library loaded at run-time. At first glance it looks like there's something else in the text segment named 'error' that shadows this variable.

foo.c:

#include <stdio.h>

const char *error = "error";
const char *error2 = "error2";

void bar(void)
{
    printf("%p\n", error2);
    printf("%p\n", error);
    printf("%s\n", error2);
    printf("%s\n", error);
}

main.c:

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

int main(int argc, char **argv) 
{
   void *lib_handle;
   void (*fn)(void);
   char *err;

   lib_handle = dlopen("./libfoo.so", RTLD_LAZY);
   if (!lib_handle) 
   {
      fprintf(stderr, "%s\n", dlerror());
      exit(1);
   }

   fn = dlsym(lib_handle, "bar");
   if ((err = dlerror()) != NULL)  
   {
      fprintf(stderr, "%s\n", err);
      exit(1);
   }

   (*fn)();

   dlclose(lib_handle);
   return 0;
}

Compilation and run output:

gcc -g -Wall -pedantic -fpic -O0 -c foo.c -o foo.o
gcc -shared -o libfoo.so  foo.o
gcc main.c -Wall -fpic -o main -ldl
./main
0x7f62bc42c82b
0xfb8953f589555441
error2
Segmentation fault (core dumped)

Is this a toolchain bug? If so, what could cause this and where should it be reported?

Was it helpful?

Solution

I believe that is as designed, a symbol already loaded will take precedence. e.g. if there's any error/error2 (or bar) symbol already loaded, the same named symbols from your shared library will not be relocated. do e.g. nm -D /lib/libc.so.6 |grep error. Your code will refer to the error symbol there, whatever that is.

However,

$nm -D /lib/libc.so.6 |grep error`
42471670 W error

This shows that glibc defines an error symbol, but it's weakly defined.

This means that if your code, at link time, defines the same symbol, yours will override any weakly defined symbols. But that does not happen when you dynamically load a library. That behavior can be overridden by setting the environment variable LD_DYNAMIC_WEAK - see man ld.so for more info.

So if you run your program like so:

 $ LD_DYNAMIC_WEAK=true ./main

it will work

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top