Question

I was just playing around with the concept of LD_PRELOAD. Seems like it works fine until I start to use the pthread library functions in my code. When I do that, I get segmentation fault. Does LD_PRELOAD has some kind of aversion to the pthread library or what?

Shown here are both program and LD_PRELOADed .so code.

Program Code

// main.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>

#define USE_PTHREADS

#define NUM_THREADS     8

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

int sum;
float total = 1;
extern int __did_libc_start_main;

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   pthread_mutex_lock( &m );
   sum++;
   total *= total + tid * 0.097891313423578;
   printf( "p%d, tid%d, total = %g, start = %d!\n", getpid(), tid, 
      total, 0 );
   pthread_mutex_unlock( &m );
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   char * p;
   char * m;

   fork();

   p = (char*)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 
     -1, 0);
   p[0] = 78;
   printf( "p = %p, p[0] = %d, pid = %d!\n", p, p[0], getpid() );
   m = (char*)malloc( 80 );
   printf( "m = %p!\n", m );
#ifdef USE_PTHREADS // If we disable this part of code, LD_PRELOAD works fine
   for(t=0; t<NUM_THREADS; t++)
   {
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }
   for(t=0; t<NUM_THREADS; t++)
    pthread_join(threads[t], NULL);

   printf( "\n\nTotal = %g\n\n", total );

   /* Last thing that main() should do */
   pthread_exit(NULL);
#endif
   printf( "\n\n%d: Done without major problems\n\n", getpid() );
   return 0;
}

LD_PRELOADed .so code

// prelib.c
#define _GNU_SOURCE

//#include <sys/syscall.h>
//#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <dlfcn.h>

typedef pid_t (*getpidType)(void);
typedef void* (*mmapType)(void *addr, size_t len, int prot, int flags,
       int fildes, off_t off);

pid_t getpid(void)
{
    static int first_time = 1;
    static getpidType f;

    printf("Hello, getpid!\n");

    if ( first_time )
    {
        f = (getpidType)dlsym(RTLD_NEXT, "getpid");
        first_time = 0;
    }

    return f();
}
void *mmap(void *addr, size_t len, int prot, int flags,
       int fildes, off_t off)
{
    static int first_time = 1;
    static mmapType f;

    printf( "My mmap!\n" );
    if ( first_time )
    {
        f = (mmapType)dlsym(RTLD_NEXT, "mmap" );
        first_time = 0;
    }

    return f( addr, len, prot, flags, fildes, off );
}

I get an error like this when USE_PTHREADS is defined.

My mmap!
<< mutex_trylock >>
<< mutex_unlock >>
Hello, getpid!
p = 0x2ab9bc969000, p[0] = 78, pid = 9763!
m = 0x179d4010!
In main: creating thread 0
My mmap!
<< mutex_trylock >>
My mmap!
<< mutex_trylock >>
<< mutex_unlock >>
Hello, getpid!
p = 0x2ab9bc969000, p[0] = 78, pid = 9762!
m = 0x179d4010!
In main: creating thread 0
My mmap!
<< mutex_trylock >>
Segmentation fault
Was it helpful?

Solution

I doubt this is your only problem, but your "first_time" hack is not synchronized and thus not thread-safe. You should be using the pthread_once function for this purpose, or roll your own version with a mutex or semaphore.

OTHER TIPS

Only thing I can imagine is:

printf( "p%d, tid%d, total = %g, start = %d!\n", getpid(), tid, total, 0 );

should be tid%ld

Maybe you are running on 64 bit and longs are not int sized. So then when it goes to print the float, it sees crap and you are crashing printf.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top