我的程序崩溃,试图解开堆栈的段错误。这是gcc错误还是不允许选项-fexceptions
和-static-libgcc
的组合?
如果出现以下情况,则不会发生崩溃:
-static-libgcc
被省略-fexceptions
被省略pthread_cleanup_push()
和pthread_cleanup_pop()
被省略g++
或gcc -x g++
(*)我在gcc 4.8.4和4.8.5上试过这个。
(*)这不适用于我们基于gcc 4.2.3的自定义构建环境之一。然而,对于基于gcc 4.2.3的不同版本的构建环境,崩溃根本不会发生!
/*
* thread_crash.c: Test case for thread unwinder crash bug.
*
* Compile (with native or V6p3, 32 or 64 bit) using:
* gcc -o thread_crash.o -c thread_crash.c -ggdb -Wall -pthread -fexceptions
* g++ -o thread_crash thread_crash.o -ggdb -Wall -lpthread -static-libgcc
*
* Expected behaviour: No output.
* Observed behaviour: Outputs "Aborted (core dumped)".
*/
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
static void cleanup(void *ptr)
{
}
void *child(void *ptr)
{
pthread_cleanup_push(cleanup, NULL);
pthread_exit(NULL);
pthread_cleanup_pop(1);
return NULL;
}
int main()
{
pthread_t foo;
pthread_create(&foo, NULL, child, NULL);
pthread_join(foo, NULL);
return 0;
}
#0 0x00007ffff72271f7 in raise () from /lib64/libc.so.6
#1 0x00007ffff72288e8 in abort () from /lib64/libc.so.6
#2 0x00000000004031be in _Unwind_SetGR ()
#3 0x000000000040587a in __gcc_personality_v0 ()
#4 0x00007ffff6feba14 in ?? () from /lib64/libgcc_s.so.1
#5 0x00007ffff6febd64 in _Unwind_ForcedUnwind () from /lib64/libgcc_s.so.1
#6 0x00007ffff7bcd240 in __pthread_unwind () from /lib64/libpthread.so.0
#7 0x00007ffff7bc7e35 in pthread_exit () from /lib64/libpthread.so.0
#8 0x0000000000400a97 in child (ptr=0x0) at thread_crash.c:46
#9 0x00007ffff7bc6e25 in start_thread () from /lib64/libpthread.so.0
#10 0x00007ffff72ea34d in clone () from /lib64/libc.so.6
答案 0 :(得分:1)
使用-fexception
进行编译时,pthread_exit()
会抛出___forced_unwind
异常以强制取消所有函数,这可以保证自动存储(也称为堆栈)清理。这是因为pthread_exit()
的目的是不返回。来自man pthread_exit
:
此功能不会返回给来电者。
另一方面,根据man pthread_cleanup_push
:
POSIX.1表示使用return,break,continue或者的效果 转到过早地留下一个块括起来的pthread_cleanup_push() 和pthread_cleanup_pop()未定义。便携式应用应该 避免这样做。
POSIX没有提到C ++异常,因为POSIX只关心C,但这是一种有根据的猜测,即在pthread_cleanup_push()
和pthread_cleanup_pop()
之间抛出异常会导致未定义的行为。