奇怪的堆栈溢出?

问题描述:

我遇到了一个奇怪的情况,将一个指针传递给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 

我一直都在用小数组来完成这种事情。奇怪的是,0x7fffffffe448 - 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 

错误信息都指向我重挫堆栈指针,但)我从来没有穿过一个在函数的入口和崩溃运行B)我传递指针,而不是实际的数组。

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

谢谢!

马特

+9

发布伪代码只会让你伪造答案。魔鬼在细节中,他们可能都很重要。 –

+2

我们可否看到'Read_Config_File'的来源?这就是问题出现的地方,在你消失的地方。 – Borealid

+0

您不测试可能失败的calloc()的返回值。 –

你已经通过将这些巨大的config_t结构体中的一个分配到它上面而炸毁了堆栈。 gdb输出中有证据的两个堆栈指针0x7fffffffe448和0x7ffffdf45428对此非常有帮助。

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

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

+0

有没有一种类似“lint”的工具可以告诉我一个函数会吞噬多少堆栈?事后看来,现在很明显的是故障是什么,但如果存在这样的问题,我很乐意知道。 – tranzmatt

+0

对于运行时检查,gcc具有-fstack-limit- *,但我知道没有任何警告编译时的堆栈分配过大。 –

简短的回答是,必须有声明为一个局部变量某处config_t,它会把它的堆栈。可能是一个错字:CONFIG声明之后丢失*

+0

这是问题所在。我忘记了在干扰数组之前,我在函数中保留了一个临时的config_t结构副本。我在其他地方移动了阵列,现在它不会发生故障。谢谢。 – tranzmatt