This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

LD_PRELOAD functions are called before _init


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]