Skip to content
Advertisement

Seg fault when app & shared lib built with -static-libstdc++

If I build a C++ app with -static-libstdc++ which loads a shared lib (via dlopen) which was also built with -static-libstdc++, then the app seg faults during dlopen.

BUT–this only happens in some setups:

  • GCC 4.7.4, 32-bit: pass
  • GCC 4.8.3, 32-bit: pass
  • GCC 4.8.4, 64-bit: pass
  • GCC 4.9.2, 64-bit: pass
  • GCC 4.9.3, 32-bit: FAIL (unless RTLD_DEEPBIND is specified)
  • GCC 4.9.3, 64-bit: pass

Findings:

  • If -static-libstdc++ is not used when building for either the shared lib or the app, it works.
  • If (RTLD_LAZY | RTLD_DEEPBIND) is passed to dlopen, it works. So I suspect the problem is related to symbol confusion/duplication between the app & .so.
  • Interestingly, if I have the code load the .so first with (RTLD_LAZY | RTLD_DEEPBIND), and then close it and re-load with only RTLD_LAZY, it also works.

Repro Steps

Code:

functions.cpp

JavaScript

main.cpp

JavaScript

Build

JavaScript

Run

JavaScript

Backtrace

JavaScript

It’s odd to me that this only seems to fail in some versions of GCC, and only for 32-bit. I have not tried GCC 5 yet.

I appreciate thoughts/suggestions.

Advertisement

Answer

If -static-libstdc++ is not used when building for either the shared lib or the app, it works.

In general, you should either avoid using -static-libstdc++, or hide all of its symbols to avoid such problems.

So I suspect the problem is related to symbol confusion/duplication between the app & .so.

Correct. In particular, the problem is that some symbols are duplicated, while others are not. We’ve had to disable STB_GNU_UNIQUE symbols for that reason.

if I have the code load the .so first with (RTLD_LAZY | RTLD_DEEPBIND), and then close it and re-load with only RTLD_LAZY, it also works.

That’s because dlclose doesn’t actually unload the library if you used it. From man dlclose:

JavaScript

You should be able to verify that this is the case by stopping the program in GDB after dlclose and looking at its /proc/$PID/maps — it’s very likely that you’ll find that libfunctions.so is still present in memory.

Advertisement