【问题标题】:Strange stack overflow?奇怪的堆栈溢出?
【发布时间】:2012-02-14 15:23:30
【问题描述】:

我遇到了一个奇怪的情况,将一个指针传递给一个结构,该结构在 struct{} 定义中定义了一个非常大的数组,一个大小约为 34MB 的浮点数组。简而言之,伪代码如下所示:

typedef config_t{
  ...
  float values[64000][64];
} CONFIG;


int32_t Create_Structures(CONFIG **the_config)
{
  CONFIG  *local_config;
  int32_t number_nodes;

  number_nodes = Find_Nodes();

  local_config = (CONFIG *)calloc(number_nodes,sizeof(CONFIG));
  *the_config = local_config;
  return(number_nodes);
}


int32_t Read_Config_File(CONFIG *the_config)
{
    /* do init work here */
    return(SUCCESS);
}


main()
{
    CONFIG *the_config;
    int32_t number_nodes,rc;

    number_nodes = Create_Structures(&the_config);

    rc = Read_Config_File(the_config);
    ...
    exit(0);
}

代码编译得很好,但是当我尝试运行它时,我会在 Read_Config_File() 下的 { 处获得一个 SIGSEGV。

(gdb) run
...
Program received signal SIGSEGV, Segmentation fault.
0x0000000000407d0a in Read_Config_File (the_config=Cannot access memory at address 0x7ffffdf45428
) at ../src/config_parsing.c:763
763 {
(gdb) bt
#0  0x0000000000407d0a in Read_Config_File (the_config=Cannot access memory at address 0x7ffffdf45428
) at ../src/config_parsing.c:763
#1  0x00000000004068d2 in main (argc=1, argv=0x7fffffffe448) at ../src/main.c:148

我一直在用较小的数组做这种事情。奇怪的是,0x7ffffffffe448 - 0x7ffffdf45428 = 0x20B8EF8,或者大约是我的浮点数组的 34MB。

Valgrind 会给我类似的输出:

==10894== Warning: client switching stacks?  SP change: 0x7ff000290 --> 0x7fcf47398
==10894==          to suppress, use: --max-stackframe=34311928 or greater
==10894== Invalid write of size 8
==10894==    at 0x407D0A: Read_Config_File (config_parsing.c:763)
==10894==    by 0x4068D1: main (main.c:148)
==10894==  Address 0x7fcf47398 is on thread 1's stack

所有错误消息都指向我破坏了堆栈指针,但是a)我从未遇到过在函数入口处崩溃的错误消息,并且b)我正在传递指针,而不是实际的数组。

有人可以帮我解决这个问题吗?我在运行内核 2.6.18 和 gcc 4.1.2 的 64 位 CentOS 机器上

谢谢!

马特

【问题讨论】:

  • 发布伪代码只会得到伪答案。魔鬼在细节中,它们可能都很重要。
  • 我们能看到Read_Config_File的来源吗?这就是问题所在,在您省略的块中。
  • 你没有测试 calloc() 的返回值,可能会失败。
  • @tranzmatt 你能像@Borealid 所说的那样粘贴Read_Config_File 的源代码以及Create_StructuresRead_Config_File 调用之间的代码(如果有的话)吗?
  • Read_Config_File 可能正在注销数组的末尾。

标签: c pointers stack-overflow


【解决方案1】:

通过将这些巨大的 config_t 结构之一分配到堆栈上,您已经炸毁了堆栈。 gdb 输出中证据的两个堆栈指针 0x7ffffffffe448 和 0x7ffffdf45428 非常暗示这一点。

$ gdb
GNU gdb 6.3.50-20050815 ...blahblahblah...
(gdb) p 0x7fffffffe448 - 0x7ffffdf45428  
$1 = 34312224

您的 ~34MB 常量与 config_t 结构的大小相匹配。默认情况下,系统不会为您提供那么多堆栈空间,因此要么将对象移出堆栈,要么增加堆栈空间。

【讨论】:

  • 是否有类似“lint”的工具可以告诉我一个函数要吞噬多少堆栈?事后看来,现在很明显故障是什么,但我很想提前知道是否存在此类问题。
  • gcc 有 -fstack-limit-* 用于运行时检查,但我不知道在编译时警告过大的堆栈分配。
【解决方案2】:

简短的回答是必须有一个config_t 声明为某处的局部变量,这会将其放入堆栈。可能是一个错字:在某处的 CONFIG 声明之后缺少 *

【讨论】:

  • 这就是问题所在。我忘记了在将数组塞入内部之前,我在函数中保留了 config_t 结构的临时副本。我将阵列移到其他地方,现在它没有段错误。谢谢。
猜你喜欢
  • 2020-12-03
  • 2013-09-04
  • 2011-03-03
  • 1970-01-01
  • 2019-05-18
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多