How to run code exactly once in LD_PRELOADed shared library?

89 views Asked by At

The following code demonstrates that when using LD_PRELOAD, the library can be loaded multiple times in the same process (constructors called multiple times and static data initialized multiple times).

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>

extern bool initialized = false;

void __attribute__ ((constructor)) setup() {
    printf("constructor %d %d %d\n", getpid(), gettid(), initialized);
    initialized = true;
}

The experiment can be run with the following commands:

$ gcc -Wall -shared -fPIC -o libtest.so lib.c

$ env LD_PRELOAD=$PWD/libtest.so sh -c ls
constructor 98928 98928 0
constructor 98928 98928 0
... rest of output of ls

Note that the PID is the same; this is not a problem due to forking. Note that the initialized variable is 0, presumably because each time the library gets loaded, the loader puts the static section in to a new place memory. I know that replacing sh -c ls with just ls would cause the library to be loaded only once in this particular case, but not generally.

How does one run code exactly once in an LD_PRELOADed library for arbitrary command?

1

There are 1 answers

7
Eric Postpischil On

When you execute sh, the library is loaded, and the constructor runs. Then, because of the -c "$cmd", the shell calls an exec routine to completely replace the process with a new program. Nearly everything about the previous program is wiped away, including the loaded libraries. Then the new program starts, so the library is loaded again, and the constructor runs again. The system is not running the constructor twice in the same program; it is two separate programs, one after the other in the same process.

I know that replacing sh -c "$cmd" with just $cmd would cause the library to be loaded only once in this particular case,…

How does one run code exactly once in an LD_PRELOADed library?

As you write, replace sh -c "$cmd" with $cmd.