代码之家  ›  专栏  ›  技术社区  ›  user2131116

缓冲区溢出时程序没有崩溃

  •  1
  • user2131116  · 技术社区  · 11 年前

    我想从键盘上读取字符串并存储在 buf 。我设置了 char buf[6] 数组,此数组最多可存储5个字符,并且 \0 .

    然后我键入 123 456 789 它包含11个字符和一个 \0 ,程序仍然可以运行,但如果我键入更长的字符串 123 456 789 123 456 789 它将在运行时崩溃。 这两个输入也超出了 缓冲器 ,但一个可以跑,另一个崩溃?

    这是我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void read_str();
    
    int main(){
        read_str();
        system("pause");
        return 0;
    }
    void read_str(){
    
        char buf[6] = {};
        scanf("%[^\n]",buf);
        printf("%d\n",strlen(buf));
        printf("%s\n",buf);
    }
    
    2 回复  |  直到 11 年前
        1
  •  3
  •   Shafik Yaghmour    11 年前

    这只是 undefined behavior 在分配的内存范围之外进行写入。它现在可能起作用,但不能指望它起作用。这个 C99 draft standard 见附件 J.2 未定义的行为 说:

    数组下标超出范围,即使对象显然可以通过 给定下标(如左值表达式a[1][7]中给定声明int a[4][5])(6.5.6)。

    请注意该部分 3.4.3 未定义的行为 它定义了段落中的术语 2. 说( 重点矿井 ):

    可能的未定义行为包括完全忽略情况并产生不可预测的结果 ,在翻译或程序执行期间以环境特征的记录方式表现(有或没有发布诊断消息),终止翻译或执行(有诊断消息的发布)。

        2
  •  3
  •   Crowman    11 年前

    真正的原因很可能是,由于您在函数调用中,您只是覆盖了堆栈的内容,并且在尝试将字符写过堆栈底部之前,您实际上无法访问不属于自己的内存。即使它没有崩溃,但这几乎总是很糟糕的,因为您覆盖了程序出于某种原因放在那里的值。毕竟,如果每次重写缓冲区时总是崩溃,那么缓冲区溢出错误就永远不会发生,我们知道它们确实会发生。

    例如,您的堆栈可能正在向下增长。当您进行函数调用时,您可能会将寄存器值、返回地址、参数值和其他东西放在堆栈中。然后,也只有到那时,你的6个字节 buf 分配。如果所有其他东西都占用了,比如说,12个字节,那么你可以向其中写入18个字符 缓冲器 仍然是唯一触动记忆的 不应该改变,但这是您的流程所拥有的。由于您的进程拥有它,所以您不会得到非法的内存访问,也不会崩溃。一旦你超过了18个字节,那么你很可能会进入你的进程不拥有的内存,你会得到一个segfault,游戏就会开始。

    C的原因是,你只是有未定义的行为,发生了一些你甚至不应该试图理解的奇怪事情。