PTHREAD_DETACH()在64位Linux上引起sigsegv



这是我情况的描述:我必须照顾我们的产品中的错误。该线程是作为joinable创建的,它必须完成其工作,终止,没有人会为其呼叫pthread_join()。因此,该线程是使用Joarable属性(默认情况下)创建的,并且在终止之前调用下一个代码:

{  pthread_detach(pthread_self()); pthread_exit(NULL); }

它的工作方式就像我遇到的所有32位Linux发行版上的魅力一样,但是在64位发行版(Ubuntu 13.04 x86_64和Debian)上引起SIGSEGV。我没有尝试使用Slackware。这是一个核心:

Core was generated by `IsaVM -s=1 -PrjPath="/home/taf/Linux_Fov_540148/Cmds"  -stgMode=1 -PR -Failover'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007f5911a7c009 in pthread_detach () from /lib/x86_64-linux-gnu/libpthread.so.0
(gdb) bt
#0  0x00007f5911a7c009 in pthread_detach () from /lib/x86_64-linux-gnu/libpthread.so.0
#1  0x000000000041310d in _kerCltDownloadThr (StartParams=0x6bfce0 <RESFOV>) at ./dker0clt.c:1258
#2  0x00007f5911a7ae9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#3  0x00007f591159f3fd in clone () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x0000000000000000 in ?? ()

我弄清楚了如何修复此错误 - 我在创建线程之前设置了create_detachable属性(带有 pthread_attr_setdetachstate()),并且可以按预期工作。

但是我的问题 - 称此代码是犯罪吗?

{  pthread_detach(pthread_self()); pthread_exit(NULL); }

pthread_detach()在通话后会做些异步做的事情,这会导致pthread_exit()带来问题吗?但是崩溃点是pthread_detach()不是pthread_exit()!我不明白这次崩溃的原因!它为什么在32位上工作?它是pthread实施中某个地方的比赛条件吗?

pthread_join()没有为此线程打电话。

事先感谢您的任何想法。

脱离本身的线程感觉不正确。通常是该线程的责任,该线程称为pthread_create(),可以在必要时创建一个独立的线程。

可能已经脱离了线程。因为试图脱离已经分离的线程会导致未指定的行为。

我的最高猜测是:

  1. 线程不止一次分离。作为快速检查,我将尝试在gdb中的pthread_detach上设置一个断点,以查看是否在此功能中传递了重复的线程ID。如果很难在gdb下运行您的应用程序,另一个选项是覆盖pthread_createpthread_detach并跟踪线程ID来检测双分离。请参阅http://hackerboss.com/overriding-system-funtions-for-for-fun-and-profit/

  2. 内存腐败。valgrind可以帮助您检测内存损坏,如果可以在其下运行应用程序。或者,如果使用-fsanitize=address,CC_19,-fsanitize=thread,请尝试使用运行时错误检查仪器,如果使用gccclang编译器还具有一系列检测此类错误的选项,请参见http://clang.llvm.org/docs/index.html。

我用可观的@maximyegorushkin提供的方法完成了研究。AddressSanitizer向我展示了我们的产品中的一个缓冲区Obverflow,但它与我的问题无关(我肯定会在以后解决,拥有这样的明智工具来捕捉错误总是很好的)。因此,决定使用LD_PRELOAD方法覆盖所有必要的pthread_xxx功能。我进行了一个简单的测试,以确保我的库按预期工作:

[HACK] Loading pthread hack.
Starting thread...!
[HACK] pthread_create: thread=7FAC6C86D700
Waiting for 2 seconds...
[HACK] pthread_self: thread=7FAC6C86D700
thread_func: thread id = 7FAC6C86D700
Thread: sin(3.26) = -0.121109
[HACK] pthread_self: thread=7FAC6C86D700
[HACK] pthread_detach: thread=7FAC6C86D700
Terminating...

所有字符串从 [hack] >由我的threadhack.so库生成。然后,我使用此库来运行我的项目,它准确地指出了问题所在:

执行代码:{ pthread_detach(pthread_self()); pthread_exit(NULL); }

调试痕迹:

[HACK] pthread_create: thread=7F403251CB00
.....
[HACK] pthread_self: thread=7F403251CB00  
[HACK] pthread_detach: thread=3251CB00    

因此,我们看到pthread_self返回了一个好线程ID,但是pthread_detach已收到它已经被弄脏(切成32位)。这怎么可能?我为我的简单工作测试应用程序作为参考和项目生成了汇编代码:

参考应用程序:

call    pthread_self
movq    %rax, %rdi
call    pthread_detach
movl    $0, %edi
call    pthread_exit

因此,我们在这里看到movq指令用于复制64位线程ID(movq %rax, %rdi)。好的,请检查我的项目的GCC生成的

movl    $0, %eax
call    pthread_self
movl    %eax, %edi
movl    $0, %eax
call    pthread_detach
movl    $0, %edi
movl    $0, %eax
call    pthread_exit

woa!我们有两个movl指令(32位),一个副本是最小有效的32位(movl %eax, %edi),而不是大多数显着的部分,它总是将零放置!(movl $0, %eax)。因此,这是造成斜纹ID的原因。我不知道为什么代码如此不同 - 编译标志是相同的。我在GCC 4.7中看到了这个错误,我在GCC 4.8中看到了此错误(Ubuntu 13.10 x86_64的最新软件包)。

至少现在我看到了什么。感谢@maxim和出色的工具。我再次学到了一个新事物。

P.S。我不知道如何向海湾合作委员会团队提交错误报告。我无法在一个小简单的应用程序上重现问题,我无法将它们交给我的项目,因为它是一个专有软件,我是不分发它的NDA-ED。

我的猜测是您在调用pthread_detach(pthread_detach(pthread_sers())的代码中,您没有PTHREAD_DETACH或PTHREAD_SELP的原型;没有原型,编译器将假定参数为int(pthread_detach)或该函数返回int(pthread_self)。

尽管进一步思考,但我更怀疑pthread_self是罪魁祸首是未定义的(返回int)或错误地定义为返回int。然后,编译器通过添加领先的32位零位。

,将其正确扩展到64位整数。

相关内容

  • 没有找到相关文章

最新更新