如何使用GCC保持堆栈变量不会在C ++中覆盖静态数组?

时间:2011-12-18 21:08:30

标签: linux gcc linker

我遇到一个问题,其中在堆栈上声明为自动变量的数组会覆盖静态声明的数组。由于尺寸和知识产权的原因,我无法引用确切的代码,但概述如下。

我有以下结构:

struct mystruct_type {
    const int list_size;
    const int* list;
};

我有这些结构的全局静态数组:

struct mystruct_type mystruct_ar[] = {
    {3, (int[]){1, 2, 3}},
    {2, (int[]){1, 3}},
    {5, (int[]){4, 2, 3, 4, 5}}
};

此数组位于已编译到库中的源文件中。

我有另一个源文件被编译到另一个具有自动数组的库中:

void my_func(void) 
{
    char my_string[1000];

    // etc...
}

如果全部链接在一起,我会看到listmystruct_ar一个的地址,与my_string重叠,当我将某些内容复制到my_string中会覆盖list中的元素,从而导致各种问题。

我对编译器和链接器如何工作的理解是静态数组及其所有子数组都属于一个内存区域,而堆栈(声明my_string的堆栈)是一个单独的非重叠区域。什么可能导致这种重叠?我可以检查什么?

我在SuSE10 Linux(x86-64_linux26)上使用GCC 4.3.2。一切都是静态的。

编辑:以下几条评论说这不编译。他们是对的。在清理我的代码片段以进行演示的过程中,我忽略了将list数组转换为int[]。这已在上面修复。

3 个答案:

答案 0 :(得分:1)

我认为这段代码不会编译。具体来说,您无法在mystruct_ar中为列表指针传递{list,of,ints}。您必须在上面单独声明每个int数组。

您需要提供一个实际演示错误的连贯样本,或者实际代码片段失败。

答案 1 :(得分:0)

堆栈的大小是在运行时确定的,而不是在编译时确定的。运行ulimit -s以查找当前最大堆栈大小,并传递参数(如ulimit -s 16384)以增加它。我的两台Linux机器都显示8192作为当前堆栈大小,尝试增加它,看看你的应用程序是否运行得更好。

答案 2 :(得分:0)

  

可能导致这种重叠的原因是什么?

你没有说你是否使用多个线程。如果是的话,my_string很可能溢出(有限的)堆栈,从而无意地重叠全局数据。

Linux上的典型堆栈为8MB,默认防护区域为1页(== 4K)。这使得你不太可能实际上溢出堆栈(8MB非常大)并且1000个元素my_string可以“跳过”#34;保护区域没有触及它(触摸保护区域会产生SIGSEGV)。

但是,您可能没有告诉我们所有相关细节。如果使用非默认属性创建线程,可能是使用小堆栈创建它们并禁用保护区域?

更糟糕的是,您可能正在创建具有固定堆栈区域的线程(通过pthread_attr_setstackaddr),并且该固定堆栈区域可能是全局数组。如果您(或您调用的某些第三方代码)执行 ,则没有任何内容可以将全局变量与其他全局变量(现在用作堆栈)以及碰撞(以及缺少保卫区域)完全有可能。

如果您使用协程式编程(基本上是用户级线程),也可以在没有线程的情况下溢出。 makecontext / swapcontext或类似的机制。