#340

dlsym(handle) returns another library's symbol when both have the same file name and RTLD_GLOBAL

Opennateberkopecopened 8d ago

When two libraries share a file name (here a/lib.so and b/lib.so) and are both opened with RTLD_GLOBAL, dlsym() on the second handle returns the first library's symbol. glibc built with gcc returns the second library's symbol. Fil-C also does with RTLD_LOCAL.

// a/lib.c (b/lib.c is the same but prints "b/lib.so")
#include <stdio.h>
void init(void) { puts("a/lib.so"); }

// main.c
#include <dlfcn.h>

int main(void) {
    void *a = dlopen("./a/lib.so", RTLD_LAZY | RTLD_GLOBAL);
    void *b = dlopen("./b/lib.so", RTLD_LAZY | RTLD_GLOBAL);
    void (*init_b)(void) = dlsym(b, "init");
    init_b();
}
$ filcc -shared -fPIC -o a/lib.so a/lib.c && filcc -shared -fPIC -o b/lib.so b/lib.c && filcc -o main main.c && ./main
a/lib.so

Expected b/lib.so. Fil-C 0.686 (optfil, linux aarch64).

Found while porting Ruby to Fil-C: Ruby's cgi/escape.so and erb/escape.so both export Init_escape, so require "erb" ran the wrong init function.

Activity

3
pizlonator8d ago

Weird!

I'll take a look.

Fil-C's dlsym just uses glibc's dlsym, for the most part. So this is a super strange bug!

nateberkopec8d ago

Thanks mate! Fil-C is a really cool project. I'm working on getting it working w/Ruby 4.0.7 so just reporting stuff as I go along.

nateberkopec8d ago

This is AI-assisted. Model: gpt-6-astra

Correction: identical file names aren't necessary. RTLD_LOCAL on the second library also reproduces it if the first is global.

a.c:

#include <stdio.h>
void Init_eval(void) { puts("a"); }

b.c is the same but prints b. main.c:

#include <dlfcn.h>
int main(void) {
    dlopen("./a.so", RTLD_LAZY | RTLD_GLOBAL);
    void *b = dlopen("./b.so", RTLD_LAZY | RTLD_LOCAL);
    void (*fn)(void) = dlsym(b, "Init_eval");
    fn();
}
filcc -shared -fPIC -o a.so a.c
filcc -shared -fPIC -o b.so b.c
filcc -o main main.c
./main

Prints a on optfil 0.686, Linux aarch64. Rebuilding all three with GCC prints b. Adding RTLD_DEEPBIND to the second dlopen also gives b with Fil-C.