You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何大型局部字符数组未触发Segment Fault(段错误)?

问题:大数组局部变量未崩溃,编译器采取了什么处理机制?

我们所学知识表明局部变量在栈上分配,不能占用过多栈空间,但以下代码示例中的程序并未崩溃,请问编译器采取了什么处理机制?

#include<iostream>

using namespace std;

int main()
{
    
    char arr[40960];

    for(auto i =0;i<40960;++i)
        arr[i]='c';

    std::cout<<sizeof(arr)<<std::endl;

    return 0;
}

gcc --version
gcc (GCC) 14.1.1 20240522
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

反汇编代码

0000000000001159 <main>:
    1159:   55                      push   %rbp
    115a:   48 89 e5                mov    %rsp,%rbp
    115d:   48 81 ec 20 a0 00 00    sub    $0xa020,%rsp
    1164:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
    116b:   00 00 
    116d:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    1171:   31 c0                   xor    %eax,%eax
    1173:   c7 85 ec 5f ff ff 00    movl   $0x0,-0xa014(%rbp)
    117a:   00 00 00 
    117d:   eb 17                   jmp    1196 <main+0x3d>
    117f:   8b 85 ec 5f ff ff       mov    -0xa014(%rbp),%eax
    1185:   48 98                   cltq
    1187:   c6 84 05 f0 5f ff ff    movb   $0x63,-0xa010(%rbp,%rax,1)
    118e:   63 
    118f:   83 85 ec 5f ff ff 01    addl   $0x1,-0xa014(%rbp)
    1196:   81 bd ec 5f ff ff ff    cmpl   $0x9fff,-0xa014(%rbp)
    119d:   9f 00 00 
    11a0:   7e dd                   jle    117f <main+0x26>
    11a2:   be 00 a0 00 00          mov    $0xa000,%esi
    11a7:   48 8d 05 92 2e 00 00    lea    0x2e92(%rip),%rax        # 4040 <_ZSt4cout@GLIBCXX_3.4>
    11ae:   48 89 c7                mov    %rax,%rdi
    11b1:   e8 7a fe ff ff          call   1030 <_ZNSolsEm@plt>
    11b6:   48 8b 15 03 2e 00 00    mov    0x2e03(%rip),%rdx        # 3fc0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    11bd:   48 89 d6                mov    %rdx,%rsi
    11c0:   48 89 c7                mov    %rax,%rdi
    11c3:   e8 78 fe ff ff          call   1040 <_ZNSolsEPFRSoS_E@plt>
    11c8:   b8 00 00 00 00          mov    $0x0,%eax
    11cd:   48 8b 55 f8             mov    -0x8(%rbp),%rdx
    11d1:   64 48 2b 14 25 28 00    sub    %fs:0x28,%rdx
    11d8:   00 00 
    11da:   74 05                   je     11e1 <main+0x88>
    11dc:   e8 6f fe ff ff          call   1050 <__stack_chk_fail@plt>
    11e1:   c9                      leave
    11e2:   c3                      ret

解答

  1. 核心原因:数组大小未超出栈空间上限
    Linux系统默认栈空间大小通常为8MB左右,你定义的数组大小是40960字节(约40KB),远小于这个上限,因此栈有足够空间分配该数组,不会触发栈溢出崩溃。

  2. 反汇编验证栈分配逻辑
    从反汇编的sub $0xa020,%rsp指令可以看出,编译器确实在栈上为数组分配了空间:0xa020换算为十进制是40992字节,其中40960字节用于数组,剩余32字节用来存放栈保护变量、循环变量等栈帧额外数据。

  3. 栈溢出保护机制的作用
    反汇编中还包含gcc默认开启的-fstack-protector栈溢出保护逻辑:

  • mov %fs:0x28,%rax将线程本地存储的随机保护值存入栈帧
  • 函数返回前通过sub %fs:0x28,%rdx检查保护值是否被篡改
  • 若检测到溢出则调用__stack_chk_fail终止程序
    但你的代码中数组没有越界访问,因此不会触发该保护机制。

补充:如果将数组大小修改为远大于8MB(比如10MB),程序会因栈空间不足崩溃;也可以通过ulimit -s命令查看或修改当前系统的栈大小限制。

内容的提问来源于stack exchange,提问作者Rain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:24:50