为啥在函数中用作局部变量时数组不会沿堆栈方向增长?

Posted

技术标签:

【中文标题】为啥在函数中用作局部变量时数组不会沿堆栈方向增长?【英文标题】:Why do arrays not grow in stack direction when used in functions as local variables?为什么在函数中用作局部变量时数组不会沿堆栈方向增长? 【发布时间】:2020-03-02 09:00:21 【问题描述】:

这可能是一个愚蠢的问题,但我想知道如果数组以某种方式填充值以使其在堆栈方向上增长怎么办(因此,如果数组是唯一的一个局部变量,那么第一个数组的元素在堆栈帧指针/基指针之后的一个字节被寻址,第二个元素在堆栈帧指针/基指针之后的两个字节被寻址,...),它不会使 C 中的堆栈溢出更安全,因为返回地址不能这么容易被覆盖(数组必须填满几乎整个 RAM,因此程序会崩溃而不是执行一些恶意代码)?

【问题讨论】:

因为索引*(array + index) 不起作用。 我必须说真的很有趣的问题。太棒了! @WeatherVane 不知道我是否相信这个解释。定义指针算术很容易,因此只需减去即可。还是我错过了什么? 主要是因为任何大小合适的数组都无法放入堆栈。所以你会使用堆,所以为什么要让事情变得复杂。您同样可以问“为什么堆栈在内存中会减少? @klutt 你也必须重写处理器的索引指令。 【参考方案1】:

如果堆栈没有完全交换所有数组的寻址模型,就无法做到这一点。这是一个可行的实施选择,但与现有的 ABI 不兼容。

您注意到的是,在某些方面,拥有一个向上增长的堆栈(向上是正数组索引的方向)在某些方面比拥有一个向下增长的堆栈更安全。然而,这并不是那么安全。考虑将具有自动存储功能的数组的地址传递给另一个函数时会发生什么。被调用者在堆栈上的位置将高于数组,因此数组的任何溢出都会溢出到被调用者的堆栈帧中,可能包括其返回地址。例如:

void foo()

    char s[4];
    strcpy(s, "hello world");

strcpy 返回时,它的返回地址可能已被存储在传递给它的地址的数组末尾之后。

【讨论】:

【参考方案2】:

“堆栈的方向”是实现的函数,而不是语言 - 语言规范甚至不假设存在堆栈。

数组索引通过向基地址添加非负偏移量并取消引用结果来工作 - 数组必须始终“向上”增长到地址增加,而不管堆栈增长方向如何。

真正使数组操作安全(r) 的唯一方法是 C 语言规范要求对所有数组访问进行边界检查并在越界访问时抛出异常.当然,C 语言规范还必须添加结构化异常处理(当前的信号处理方法严重不足)。

这样的添加是...不太可能

【讨论】:

规范确实允许编译器进行数组边界检查......编译器实际实现它并不常见 @M.M:将措辞更改为“要求”。

以上是关于为啥在函数中用作局部变量时数组不会沿堆栈方向增长?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我在函数中声明一个名称为全局数组的局部数组时,bash 会引发未绑定变量警告?

堆栈动态和堆栈动态数组

4.6指针变量作参数

为啥要为局部变量保留堆栈空间?

C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?

码海拾遗:内存四区