【问题标题】:Possible Stack Corruption可能的堆栈损坏
【发布时间】:2010-10-19 18:08:28
【问题描述】:

参考我之前关于GDB not pinpointing the SIGSEGV point的问题,

我的线程代码如下:

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);
}

编辑:在运行线程代码中有一个 exit(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

【问题讨论】:

  • 您需要发布更多代码。所有多汁的部分都不见了。
  • 这是 valgrind 报告的唯一错误吗?如果它报告其他人,从第一个开始。
  • 在运行线程代码中有一个 exit(0) 甚至不是一个可以接受的解决方案。

标签: c pthreads semaphore


【解决方案1】:

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

如果仍然失败,您将可以更轻松地调试它。

既然您说调用exit 而不是返回不会产生错误,这表明您在启动runner 时损坏了堆栈上的返回地址。通过调用exit,您不必依赖此内存区域来访问退出函数(如果您返回了pthread_exit,则pthread 库代码将调用runner)。我认为 valgrind 输出不是 100% 准确的——不是由于 valgrind 中的任何错误,而是因为您触发错误的位置以及您触发的错误类型使得很难确定谁调用了什么.

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

-fstack-protector-all -Wstack-protector

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

你也可以试试:

-fno-omit-frame-pointer

【讨论】:

    【解决方案2】:

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

    • 在堆栈中存储一个指向元素的指针,并在对象已经超出范围后使用它。
    • 缓冲区溢出,例如在堆栈上有 char buffer[20] 并在边界外写入(sprintf 是实现这一目标的绝佳方式)。
    • 错误转换,即在堆栈上有一个基类 A,将其转换为派生类并使用它。

    【讨论】:

    • 他的堆栈似乎没有损坏。
    【解决方案3】:

    使用 valgrind 或等效的内存检查工具来解决这个问题。 别猜了。还要停止发布不完整的代码,特别是如果您不知道它是否有问题。该错误可能在此功能之外。例如,信号量可能没有初始化。

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

    【讨论】:

    • 信号量已初始化,Valgrind 输出已发布。
    • 只有在 valgrind 没有抱怨的情况下,我才会相信你。说真的,别猜了。
    • 我已经记下了主要代码。如果不在这里转储整个源文件,我不知道我还能发布什么。
    • @Kedar:那就这样做吧。如果代码很大,请将其发布到 pastebin.com 并发布指向该链接的链接。
    • 让 gdb 将程序运行到 pthread_create 行,然后使用 'dissass $eip, $eip+40' 显示调用 pthread_create 的 main 的汇编代码。另外,也许用 -Wall -Wextra 编译你的代码。
    猜你喜欢
    • 2013-06-26
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2014-01-07
    • 1970-01-01
    相关资源
    最近更新 更多