I want to use the LD_PRELOAD mechanism GNU's dynamic loader to inject code into other binaries. In my code I use a static object to have code executed right at the start and the very end of the augmented program (called Prog later on). Execution order of static initialisers should not concern me as I do not access any data of Prog and I also don't care when exactly my code runs as long as it's "close enough" to the start/end of Prog's "main".
The problem is that for some binaries this approach works fine while for others the destructor of the static object is simply not invoked.
#include <iostream>
namespace {
struct Stat {
Stat() { std::cerr << "Ctor" << std::endl; }
~Stat() { std::cerr << "Dtor" << std::endl; }
};
}
Stat s;
Compilation:
$ g++ -shared -fpic -o ~/preload.so preload.cc
Usage:
$ LD_PRELOAD=~/preload.so /bin/true
Ctor
Dtor
$ LD_PRELOAD=~/preload.so /bin/sleep 1
Ctor
In the first case with true
everything works as expected but in the second case (and most/all others) the destructor is never called. I excluded problems with the standard streams beeing destructed "too early" by replacing the string output with sleep
… works for true
, fails for sleep
. (Edit: Ignore that last part. I messed up with the compilation and ran the version without sleep
yet again. sleep
actually works, so @dms is right. It does not explain the doubly printed "Ctor" in gdb, but I don't care too much about that artifact.)
Weirder still. When I try to run the examples in gdb (with set env LD_PRELOAD ...
), "Ctor" is printed twice. If I set a breakpoint at Stat
it triggers only after the first time "Ctor" is output. A breakpoint on ~Stat
does trigger but still no output.
There's a similar question about static object dtors in DLLs. The answers there are either Windows specific or imply that static dtors are never called for dynamically loaded libraries which obviously is not true in my case.