Description of problem: Using gcc6.3 libasan may - under certain circumstances - cause dlopen fail to find the .so library when only the name of the library is used in the call to dlopen (not the relative path). Version-Release number of selected component (if applicable): devtoolset-6-gcc-6.3.1-3.1.el7.x86_64 devtoolset-6-libasan-devel-6.3.1-3.1.el7.x86_64 How reproducible: Alaways Steps to Reproduce: 1. #include <dlfcn.h> #include <iostream> int main() { void *handle = dlopen("libb.so", RTLD_NOW); if (handle == NULL) { std::cout << "Failed to load libb.so" << std::endl; } } #mkdir lib #g++ --sanitize=address -Wl,-rpath='$ORIGIN/lib' -Wl,--enable-new-dtags -ldl -o main main.cpp #cd lib; Create libb.so: int foo() { return 1; } g++ -fPIC -shared b.C -o libb.so Actual results: strace ./main 2>&1 | grep libb.so open("/opt/rh/devtoolset-6/root/usr/lib/../lib64/tls/libb.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) : <snipped> : open("/usr/lib64/libb.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) write(1, "Failed to load libb.so\n", 23Failed to load libb.so Expected results: strace ./main 2>&1 | grep libb.so open("/opt/rh/devtoolset-6/root/usr/lib64/tls/libb.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("/root/cc/lib/libb.so", O_RDONLY) = 3 Additional info: Libasan intercepts dlopen call and the libasan's RUNPATH is taken into account, not the binary one. Running it through strace, it failed to load libb.so
I think the libasan dlopen interceptor could be turned into a tail call, which would address the issue. #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ if (flags()->strict_init_order) { \ StopInitOrderChecking(); \ } The above probably could just as well happen before the dlopen call.
(In reply to Florian Weimer from comment #4) > I think the libasan dlopen interceptor could be turned into a tail call, > which would address the issue. > > #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) > \ > if (flags()->strict_init_order) { > \ > StopInitOrderChecking(); > \ > } > > The above probably could just as well happen before the dlopen call. I don't see how. The interceptor does some work before the dlopen call and other work after it: INTERCEPTOR(void*, dlopen, const char *filename, int flag) { void *ctx; COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0); COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag); void *res = REAL(dlopen)(filename, flag); Symbolizer::GetOrInit()->InvalidateModuleList(); COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); return res; }