2012-09-09 35 views
5

Tôi đang cố gắng chuyển các cuộc gọi đến pthread_cond_broadcast bằng cách sử dụng cơ chế LD_PRELOAD. Hàm pthread_cond_broadcast xen kẽ của tôi chỉ gọi pthread_cond_broadcast gốc. Tuy nhiên, đối với một mã pthread rất đơn giản, nơi cả pthread_cond_wait và pthread_cond_broadcast được gọi, tôi hoặc là kết thúc với một segfault trong glibc (cho glibc 2.11.1) hoặc chương trình bị treo (đối với glibc 2.15). Bất kỳ manh mối nào đang diễn ra?pthread_cond_broadcast bị hỏng với dlsym?

Mã interposition (mà được biên soạn như một thư viện chia sẻ):

#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <dlfcn.h> 

static int (*orig_pthread_cond_broadcast)(pthread_cond_t *cond) = NULL; 

__attribute__((constructor)) 
static void start() { 
    orig_pthread_cond_broadcast = 
     (int (*)()) dlsym(RTLD_NEXT, "pthread_cond_broadcast"); 
    if (orig_pthread_cond_broadcast == NULL) { 
     printf("pthread_cond_broadcast not found!!!\n"); 
     exit(1); 
    } 
} 

__attribute__((__visibility__("default"))) 
int pthread_cond_broadcast(pthread_cond_t *cond) { 
    return orig_pthread_cond_broadcast(cond); 
} 

Chương trình pthread đơn giản:

#include <stdio.h> 
#include <pthread.h> 
#include <unistd.h> 

pthread_mutex_t cond_mutex; 
pthread_cond_t cond_var; 
int condition; 

void *thread0_work(void *arg) { 
    pthread_mutex_lock(&cond_mutex); 
    printf("Signal\n"); 
    condition = 1; 
    pthread_cond_broadcast(&cond_var); 
    pthread_mutex_unlock(&cond_mutex); 
    return NULL; 
} 

void *thread1_work(void *arg) { 
    pthread_mutex_lock(&cond_mutex); 
    while (condition == 0) { 
     printf("Wait\n"); 
     pthread_cond_wait(&cond_var, &cond_mutex); 
     printf("Done waiting\n"); 
    } 
    pthread_mutex_unlock(&cond_mutex); 
    return NULL; 
} 

int main() { 
    pthread_t thread1; 

    pthread_mutex_init(&cond_mutex, NULL); 
    pthread_cond_init(&cond_var, NULL); 

    pthread_create(&thread1, NULL, thread1_work, NULL); 

    // Slowdown this thread, so the thread 1 does pthread_cond_wait. 
    usleep(1000); 

    thread0_work(NULL); 

    pthread_join(thread1, NULL); 

    return 0; 
} 

EDIT:

Đối với glibc 2.11.1, gdb BT cung cấp:

(gdb) set environment LD_PRELOAD=./libintercept.so 
(gdb) run 
Starting program: /home/seguljac/intercept/main 
[Thread debugging using libthread_db enabled] 
[New Thread 0x7ffff7436700 (LWP 19165)] 
Wait 
Signal 
Before pthread_cond_broadcast 

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff79ca0e7 in [email protected]@GLIBC_2.3.2() from /lib/libpthread.so.0 
(gdb) bt 
#0 0x00007ffff79ca0e7 in [email protected]@GLIBC_2.3.2() from /lib/libpthread.so.0 
#1 0x00007ffff7bdb769 in pthread_cond_broadcast() from ./libintercept.so 
#2 0x00000000004008e8 in thread0_work() 
#3 0x00000000004009a4 in main() 

EDIT 2:

(Đã giải quyết) Như đề xuất của R .. (cảm ơn!), Vấn đề là trên pthread_cond_broadcast nền tảng của tôi là một biểu tượng được phiên bản, và dlsym đưa ra phiên bản sai. Blog này giải thích tình trạng này rất chi tiết: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/

+0

Nếu bạn chạy nó dưới một trình gỡ lỗi những gì hiện các backtr ace trông như thế nào? Bạn đã thử bước qua mã chưa? –

+3

Tôi nhận thấy đó là biểu tượng được phiên bản. Có thể 'dlsym' đưa cho bạn phiên bản sai? –

Trả lời

1

Cuộc gọi thông qua chức năng của bạn dường như kết thúc trong một phiên bản khác nhau của hàm:

With LD_PRELOAD: __pthread_cond_broadcast_2_0 (cond=0x804a060) at old_pthread_cond_broadcast.c:37 
Without LD_PRELOAD: [email protected]@GLIBC_2.3.2() at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/pthread_cond_broadcast.S:39 

Vì vậy, tình hình của bạn cũng tương tự như câu hỏi này, tức là bạn đang nhận được phiên bản tương thích của các chức năng pthread: symbol versioning and dlsym

trang này cung cấp cho một cách để giải quyết vấn đề, mặc dù một chút phức tạp: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/