为什么在堆栈中为局部变量分配的内存多于C++中所需的内存?

Arp*_*pit 6 c c++ memory gcc memory-management

我正在阅读缓冲区溢出.我发现有关堆栈上局部变量的内存分配的一个奇怪的事情

int f1 ()
{
    char string1[12];
    char string2[4];
}
Run Code Online (Sandbox Code Playgroud)

这里分配发生在堆栈上.

现在,在GCC中, string2被分配了4个字节,但是如果我声明除了2的幂(最多16个)之外,则由编译器分配16个字节.这意味着如果我在3,5,6,7,....,15个字节中分配string2,那么它由编译器分配16个字节,但如果我分配2的幂,如1,2,4,8 ......然后它被分配完全相同的大小.如果我分配超过16个字节(不是2的幂),那么它分配32个字节(我估计高达32个字节).

而在Visual Studio中,如果我分配1个字节,则分配9个字节,如果从2-4个字节分配,则分配12个字节,如果从5-8个字节开始,则编译器分配16个字节.

任何人都知道为什么这样的任务???

Atleast在Visual Studio中,如果有缓冲区溢出,我会收到调试错误,但在gcc中没有任何反应.GCC仅在发生过大的溢出时才提供分段故障.

Han*_*ant 13

堆栈帧大小受存储器对齐选择的影响,对于32位代码通常是4的倍数,对于64位代码通常是8的倍数.

两个编译器都可以包含使用canary进行堆栈帧损坏检查,堆栈顶部的额外32位值,在函数入口处初始化并在函数出口处进行检查.如果更改了canary值,则会发生程序中止,因为堆栈帧可能被恶意代码损坏,可能会更改函数返回地址并使其返回到任意位置.一种非常流行的恶意软件注入矢量.

MSVC具有/ RTC选项,默认情况下在Debug配置中启用.在每个局部变量之间添加这些金丝雀.因此它可以检测每个变量上的缓冲区溢出问题.

这些金丝雀当然需要额外的空间,影响堆栈框架的大小.


Man*_*726 5

多数民众赞成由于记忆 - 对齐.CPU更容易访问内存地址,这是所请求数据大小的倍数.
因此,编译器使用明确的字节填充结构以对齐结构.例如:

struct foo
{
    char a
    int b , c;
    short d;
    bool e;
    double f;
};
Run Code Online (Sandbox Code Playgroud)

理论上,该结构的大小是(假设大小bool为1字节,char1字节,int4字节,short2字节,double8字节)20字节.但实际上,编译器会在结构中添加"空洞"来对齐内存:

         0 | 1 | 2 | 3
-----------+---+---+---
0x0000 | a |   |   |
-----------+---+---+---
0x0004 | b | b | b | b
-----------+---+---+---
0x0008 | c | c | c | c
-----------+---+---+---
0x000C | d | d |   |
-----------+---+---+---
0x0010 | e |   |   |
-----------+---+---+---
0x0014 | f | f | f | f
-----------+---+---+---
0x0018 | f | f | f | f
-------+---+---+---+---
Run Code Online (Sandbox Code Playgroud)