2014-10-04 89 views
1

我有一些應用程序需要使用共享庫來編寫擴展。在我的共享庫中,我需要使用線程。主應用程序既不使用與線程庫(例如libpthread.so)鏈接的線程。非線程共享庫非線程應用程序

由於第一次測試顯示我的庫導致主應用程序崩潰。如果我使用LD_PRELOAD黑客崩潰消失:

LD_PRELOAD=/path/to/libpthread.so ./app 

在那裏我有沒有段錯誤不LD_PRELOAD黑客唯一的操作系統是OS X.在其他它只是崩潰。我測試過:Linux,FreeBSD,NetBSD。

我的問題是:有沒有辦法讓我的線程共享庫安全的非線程應用程序,而不改變主應用程序和LD_PRELOAD黑客?

要重現該問題我寫簡單的例子:

mylib.c

#include <pthread.h> 
#include <assert.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

void *_thread(void *arg) { 
    int i; 
    struct addrinfo *res; 

    for (i=0; i<10000; i++) { 
     if (getaddrinfo("localhost", NULL, NULL, &res) == 0) { 
      if (res) freeaddrinfo(res); 
     } 
    } 

    pthread_mutex_lock(&mutex); 
    printf("Just another thread message!\n"); 
    pthread_mutex_unlock(&mutex); 

    return NULL; 
} 

void make_thread() { 
    pthread_t tid[10]; 
    int i, rc; 

    for (i=0; i<10; i++) { 
     rc = pthread_create(&tid[i], NULL, _thread, NULL); 
     assert(rc == 0); 
    } 

    void *rv; 
    for (i=0; i<10; i++) { 
     rc = pthread_join(tid[i], &rv); 
     assert(rc == 0); 
    } 
} 

的main.c

#include <stdio.h> 
#include <dlfcn.h> 

int main() { 
    void *mylib_hdl; 
    void (*make_thread)(); 

    mylib_hdl = dlopen("./libmy.so", RTLD_NOW); 
    if (mylib_hdl == NULL) { 
     printf("dlopen: %s\n", dlerror()); 
     return 1; 
    } 

    make_thread = (void (*)()) dlsym(mylib_hdl, "make_thread"); 
    if (make_thread == NULL) { 
     printf("dlsym: %s\n", dlerror()); 
     return 1; 
    } 

    (*make_thread)(); 
    return 0; 
} 

的Makefile

all: 
    cc -pthread -fPIC -c mylib.c 
    cc -pthread -shared -o libmy.so mylib.o 
    cc -o main main.c -ldl 

clean: 
    rm *.o *.so main 

而且所有一起:https://github.com/olegwtf/sandbox/tree/bbbf76fdefe4bacef8a0de7a2475995719ae0436/threaded-so-for-non-threaded-app

$ make 
cc -pthread -fPIC -c mylib.c 
cc -pthread -shared -o libmy.so mylib.o 
cc -o main main.c -ldl 

$ ./main 
*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000001614c40 *** 
Segmentation fault 

$ ldd libmy.so | grep thr 
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe7e2591000) 

$ LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 
Just another thread message! 

回答

0

gdb有助於理解本示例中的內容。

3次嘗試後gdb顯示應用程序總是在libc中的rewind.c行36處崩潰。由於測試在Debian 7上運行,libc實現是eglibc。在這裏你可以看到倒帶的第36行。C:
http://www.eglibc.org/cgi-bin/viewvc.cgi/branches/eglibc-2_13/libc/libio/rewind.c?annotate=12752
_IO_acquire_lock()是一個宏和grepping eglibc源後,我發現它被定義2個地方:

簡評供第一說Generic version和第二NPTL version,其中NTPL是本地POSIX線程庫。因此,首先爲這個和其他幾個宏以及第二個線程實現首先定義了非線程實現。

當我們的主應用程序未與pthreads鏈接時,它會啓動並加載_IO_acquire_lock()和其他宏的第一個非線程實現。然後它打開我們的線程共享庫並執行它的功能。這個函數使用_IO_acquire_lock()已經加載的和非線程安全的版本。但實際上應該使用由pthread定義的線程兼容版本。這是segfault發生的地方。

這是它在Linux上的工作原理。 * BSD的情況更令人傷心。在FreeBSD上,你的程序會在線程庫試圖創建新線程後立即掛起。在NetBSD而不是掛斷程序將終止與SIGABRT。

回答主要問題:是否可以使用與pthreads沒有鏈接的應用程序中的線程共享庫?
一般 - 沒有。特別是這取決於libc的實現。例如,對於OS X,這將毫無問題地工作。對於Linux,如果您不使用使用由pthreads重新定義的特殊宏的libc函數,則這將起作用。但如何知道哪些用途?好的,你可以做1 + 1,這看起來很安全。在* BSD上,無論你的線程做什麼,你的程序都會立即崩潰或掛起。

1

我的問題是:有沒有辦法讓我的線程共享庫安全 對於非線程應用程序,而主要的應用 和LD_PRELOAD黑客的變化?

不,這些是您可以使其工作的兩種方式。既沒有到位,你的程序是無效的。

+0

-1,答案根本就是錯的。 – 2014-10-04 11:58:39

+0

@JensGustedt:'-pthread'不是'-lpthread',即它是「特殊的」。它取決於實現,但用'-pthread'編譯你的程序可能會添加預處理器定義,這會改變標準庫的行爲。也許我應該改變我的答案,即使LD_PRELOAD技巧使得程序無效,儘管它顯然適用於某些人。但是它可能不是可移植的(即使在通常支持LD_PRELOAD的系統中也是如此)。 – 2014-10-04 12:43:34

1

dlopen應該做正確的事情,並打開您自己的所有圖書館.so依賴於。

實際上,如果我註釋掉放置在線程函數中的地址查找代碼,那麼您的代碼對我來說很有用。因此,加載pthread庫完美工作。

如果我運行包含查找的代碼,valgrind告訴我崩潰低於getaddrinfo

所以問題不是沒有加載庫,他們的初始化代碼不會執行,或者沒有按照正確的順序。

+0

更清楚的是:在我的lib中,我需要使用getaddrinfo(),而不是像這個例子那樣,但無論如何, – 2014-10-04 10:48:20

+0

另外,我可以通過在'dlopen'中添加'RTLD_GLOBAL'來讓你的例子工作。標誌。但這似乎重新初始化了很多,所以創業變得非常緩慢。 – 2014-10-04 11:57:57