【问题标题】:stack corruption in coredump ? gcc/ccoredump 中的堆栈损坏? gcc/c
【发布时间】:2011-02-21 19:19:26
【问题描述】:

当我尝试使用信号处理程序将全局数据转储到文本文件并生成核心文件时,我注意到一个奇怪的问题。我希望转储到文件中的数据与核心文件中的数据相同(它是相同的全局数据)

在头文件 foo.h 中

extern char buffer[100][80] ; // Hundred records each of length 80 characters

在 foo.c 中

char buffer[100][80];

.. in a loop ..
snprintf(buffer[i],80,"%s:%d recorded idx = %d\n",__FUNCTION__,__LINE__,i);

在 signal_handler.c 中

.. in a loop ..
fprintf(..dump data to text file..)

数据已经转储到文本文件了。我在 gdb 中运行程序,然后通过 kill 发出 ABRT 信号(我正在处理的信号)。在 gdb 中我看到了

gdb) p &buffer[0]
$3 = (char (*)[80]) 0x1002c8970 

我继续并生成核心文件。在核心转储中,我看到了

(gdb) p &buffer[0]
$2 = (char (*)[80]) 0x1002c9a80 

两个位置相差1110。

我的问题是为什么我会在核心文件中看到这种差异?任何线索将不胜感激!

谢谢 约翰

编辑澄清一下,问题不在于通过 GDB 生成核心 没有信号处理程序的完整代码来隔离问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100
char buffer[100][80];

int main()
{
int i = 0;
int idx = 0;
FILE *fp = NULL;
fp = fopen("test.txt","w");
if (!fp)
    exit(1);

for (i=0; i < 5500; i++) {
    snprintf(buffer[idx],80,"%s:%d idx = %d\n",__FUNCTION__, __LINE__, i);
    idx = ((idx + 1)% MAX);
}
for (i = 0 ; i < MAX; i++)
    fprintf(fp,"%s",buffer[i]);

fclose(fp);
abort();
return 0;

}

问题不是我在GDB中运行的时候,问题是在生成的core文件中,

gdb) p 缓冲区[0]

$2 "c0 - idx = 54\n", '\0' , "main:20 0x7ef9524"

缓冲区偏移了 1110 个字节。我曾使用 GDB 检查缓冲区是否已损坏。很抱歉造成混乱。

【问题讨论】:

  • 不是您问题的答案,而是您正在做的事情滥用了信号机制。 POSIX 定义了一长串它认为“不安全”的函数,并且该列表几乎包括所有进行 I/O 的函数。它继续说,如果信号中断了不安全函数的执行并且处理程序调用了不安全函数,则行为未定义。您应该在信号处理程序中做的最多的事情是设置一个标志以指示您的转储到文件操作需要发生然后返回。主程序中的某些东西应该处理它。
  • 上面的源码不可编译(缺少MAX)。如果我添加'#define MAX 100',它会产生预期的结果:'(gdb) p buffer[0] $1 = "main:18 idx = 5400\n", '\000' '。跨度>
  • 将 gdb 更新到下一个版本似乎可以解决问题。我想知道为什么。

标签: gcc gdb


【解决方案1】:

请提供一个独立的示例。当内核从 GDB 外部生成时,我可以解释不同的地址,但从 GDB 内部生成时则不能。

这是我看到的:

$ cat foo.c 
#include <stdio.h>
#include <stdlib.h>

char buf[100][80];

int main()
{
  sprintf(buf[0], "hello");
  sprintf(buf[1], "hello again");

  abort();
}


$ gcc -g  foo.c -fPIC -pie   # PIE executable so its address can be randomized

$ gdb -q a.out 
Reading symbols from /tmp/a.out...done.
(gdb) r

Program received signal SIGABRT, Aborted.
0x00007ffff7a8ca75 in raise () at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

(gdb) p &buf[0]
$1 = (char (*)[80]) 0x7ffff81ff060
(gdb) sig SIGABRT

Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
(gdb) q

$ gdb -q a.out core
Reading symbols from /tmp/a.out...done.
[New Thread 20440]
Core was generated by `/tmp/a.out'.
Program terminated with signal 6, Aborted.
#0  0x00007ffff7a8ca75 in raise () at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

(gdb) p &buf[0]
$1 = (char (*)[80]) 0x7ffff81ff060  # same address as before
(gdb) q

$ ./a.out
Aborted (core dumped)

$ gdb -q a.out core
Reading symbols from /tmp/a.out...done.
[New Thread 20448]

Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
#0  0x00007fef9dcb5a75 in raise () at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

(gdb) p &buf[0]
$1 = (char (*)[80]) 0x7fef9e428060  # different address due to ASLR

【讨论】:

  • 谢谢!我已经编辑了澄清问题的帖子。我对馅饼(或 fpie)一无所知。不过我不使用它构建。
  • 我将此标记为答案,因为这是造成差异的合乎逻辑的原因。尽管我没有使用 pie(或 fpie),但它可能对其他一些人进行调试很有用。谢谢!
猜你喜欢
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多