这是我情况的描述:我必须照顾我们的产品中的错误。该线程是作为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()
,可以在必要时创建一个独立的线程。
可能已经脱离了线程。因为试图脱离已经分离的线程会导致未指定的行为。
我的最高猜测是:
-
线程不止一次分离。作为快速检查,我将尝试在
gdb
中的pthread_detach
上设置一个断点,以查看是否在此功能中传递了重复的线程ID。如果很难在gdb
下运行您的应用程序,另一个选项是覆盖pthread_create
和pthread_detach
并跟踪线程ID来检测双分离。请参阅http://hackerboss.com/overriding-system-funtions-for-for-fun-and-profit/ -
内存腐败。
valgrind
可以帮助您检测内存损坏,如果可以在其下运行应用程序。或者,如果使用-fsanitize=address
,CC_19,-fsanitize=thread
,请尝试使用运行时错误检查仪器,如果使用gcc
。clang
编译器还具有一系列检测此类错误的选项,请参见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位零位。