gcc是否支持使用-fexceptions的-static-libgcc?

时间:2018-05-15 10:42:58

标签: c++ linux gcc pthreads

我的程序崩溃,试图解开堆栈的段错误。这是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;
}

从gdb

的Backtrace
#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

1 个答案:

答案 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()之间抛出异常会导致未定义的行为。