2014-10-04 103 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