LD_PRELOAD functions are called before _init

Mark Hills mark.hills@framestore.com
Fri Sep 19 10:51:00 GMT 2014


I am finding that when LD_PRELOAD is used, calls to symbols are commonly 
(incorrectly?) invoked before the _init function.

See the minimal example below; where fopen64() is invoked before the 
_init.

This makes it impossible to use _init as a 'constructor'. Am I expecting a 
guarantee that does not exist?

In practice, my problem is this completely prevents wrapping of fopen() in 
a commercial application:

* this application provides a new malloc() by linking against 
  libjemalloc.so

* the new malloc() function takes a lock and makes a call to fopen()

* without the constructor, our implementation of fopen() must call 
  dlsym(), but this recursively calls malloc() and deadlocks

Is there are better practice to 'initialise' this, or is some bug mangling 
the expected ordering?

This is on Scientific Linux 6.5 (a derivative of RedHat 6.5, see version 
below)

Advice appreciated -- thanks.

-- 
Mark



/*
 * Demonstrate ordering of calls in LD_PRELOAD
 *
 *   gcc -g -o basic.so basic.c -fPIC -Wall -ldl -shared
 */

#define _GNU_SOURCE
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>

static FILE* (*real_fopen64)(const char*, const char *) = NULL;

static __attribute__((constructor)) void do_init(void)
{
	real_fopen64 = dlsym(RTLD_NEXT, "fopen64");
	assert(real_fopen64);
}

FILE *fopen64(const char *pathname, const char *mode)
{
	assert(real_fopen64);
	return (*real_fopen64)(pathname, mode);
}



$ ldd ./basic.so 
        linux-vdso.so.1 =>  (0x00007fff1f367000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f723172e000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f723139a000)
        /lib64/ld-linux-x86-64.so.2 (0x000000344ee00000)



$ export LD_PRELOAD=./basic.so
$ /bin/ls
ls: basic.c:21: fopen64: Assertion `real_fopen64' failed.
Abort (core dumped)



(gdb) bt
#0  0x000000344f632925 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x000000344f634105 in abort () at abort.c:92
#2  0x000000344f62ba4e in __assert_fail_base (fmt=<value optimized out>, assertion=0x7f9c378ed6e6 "real_fopen64", file=0x7f9c378ed6de "basic.c", line=<value optimized out>, function=<value optimized out>) at assert.c:96
#3  0x000000344f62bb10 in __assert_fail (assertion=0x7f9c378ed6e6 "real_fopen64", file=0x7f9c378ed6de "basic.c", line=21, function=0x7f9c378ed6f3 "fopen64") at assert.c:105
#4  0x00007f9c378ed66a in fopen64 (pathname=0x3451e162f6 "/proc/filesystems", mode=0x3451e161eb "r") at basic.c:21
#5  0x0000003451e0cd2d in init_selinuxmnt () at init.c:49
#6  init_lib () at init.c:118
#7  0x0000003451e15cb6 in __do_global_ctors_aux () from /lib64/libselinux.so.1
#8  0x0000003451e04fa3 in _init () from /lib64/libselinux.so.1
#9  0x00007f9c378c84c8 in ?? ()
#10 0x000000344ee0e555 in call_init (main_map=0x344f021188, argc=1375849744, argv=0x7fffc3f70418, env=0x7fffc3f70428) at dl-init.c:70
#11 _dl_init (main_map=0x344f021188, argc=1375849744, argv=0x7fffc3f70418, env=0x7fffc3f70428) at dl-init.c:134
#12 0x000000344ee00b3a in _dl_start_user () from /lib64/ld-2.12.so
#13 0x0000000000000001 in ?? ()
#14 0x00007fffc3f7230a in ?? ()
#15 0x0000000000000000 in ?? ()



$ cat /etc/redhat-release
Scientific Linux release 6.5 (Carbon)
$ rpm -q glibc
glibc-2.12-1.132.el6_5.2.x86_64



More information about the Libc-help mailing list