可能的堆栈损坏

参考我之前关于GDB未查明SIGSEGV点的问题 ,

我的线程代码如下:

void *runner(void *unused) { do { sem_wait(&x); ... if(/*condition 1 check*/) { sem_post(&x); sleep(5); sem_wait(&x); if(/*repeat condition 1 check; after atleast 5 seconds*/) { printf("LEAVING...\n"); sem_post(&x); // putting exit(0); here resolves the dilemma return(NULL); } } sem_post(&x); }while(1); } 

主要代码:

 sem_t x; int main(void) { sem_init(&x,0,1); ... pthread_t thrId; pthread_create(&thrId,NULL,runner,NULL); ... pthread_join(thrId,NULL); return(0); } 

编辑:在转轮线程代码中有一个退出(0),使故障消失。


堆栈损坏背后的原因是什么?

GDB输出: (0xb7fe2b70是转轮线程ID)

 LEAVING... Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7fe2b70 (LWP 2604)] 0x00000011 in ?? () 

Valgrind输出:

 ==3076== Thread 2: ==3076== Jump to the invalid address stated on the next line ==3076== at 0x11: ??? ==3076== by 0xA26CCD: clone (clone.S:133) ==3076== Address 0x11 is not stack'd, malloc'd or (recently) free'd ==3076== ==3076== ==3076== Process terminating with default action of signal 11 (SIGSEGV) ==3076== Bad permissions for mapped region at address 0x11 ==3076== at 0x11: ??? ==3076== by 0xA26CCD: clone (clone.S:133) ==3076== Address 0x11 is not stack'd, malloc'd or (recently) free'd 

使用main函数编写一个新的源文件,该函数执行与此处发布的main相同的操作,除了使用pthread_create只调用该函数。 看看您是否可以独立于使用线程重新创建问题。 从事物看起来你的信号量应该仍然可以在单线程环境中正常工作。

如果仍然失败,您将更容易调试它。

因为你说调用exit而不是返回没有产生错误,所以它表明你已经破坏了runner启动时堆栈上的返回地址。 通过调用exit您不依赖于此内存区域来访问一个退出函数(如果您已经返回pthread_exit,则会调用已调用runner的pthread库代码)。 我认为valgrind输出不是100%准确 – 不是由于valgrind的任何错误,而是因为你触发错误的地方加上你触发的错误类型使得很难确定谁叫什么。

您可能感兴趣的一些gcc标志:

 -fstack-protector-all -Wstack-protector 

如果没有-f选项,则警告选项不起作用。

您可能还想尝试:

 -fno-omit-frame-pointer 

代码中缺少所有重要部分,但堆栈损坏的最常见原因是:

  • 存储指向堆栈上元素的指针,并在对象已经超出范围之后使用它。
  • 缓冲区溢出,就像在堆栈上有一个char buffer[20]并在边界外写字一样( sprintf是一种很棒的方法来实现它)。
  • 错误转换,即在堆栈上具有基类A,将其转换为派生类并使用它。

使用valgrind或等效的内存检查工具来搞清楚。 别猜了。 也停止发布不完整的代码,特别是如果你不知道它是否有问题。 该错误可能在此function之外。 例如,可能信号量未初始化。

从valgrind输出,我可以建议你的pthread_create()行必须包含一个无效的函数指针。 所以pthread会跳转到那个虚假的地址,然后崩溃。 显然没有堆栈……