【问题标题】:Program didn't crash when buffer overflow缓冲区溢出时程序没有崩溃
【发布时间】:2013-09-28 02:39:19
【问题描述】:

我想从键盘读取一个字符串并存储在 buf 中。我设置了一个char buf[6]数组,这个数组最多可以存储5个字符和\0。

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

这是我的代码:

#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);
}

【问题讨论】:

    标签: c windows undefined-behavior


    【解决方案1】:

    这只是undefined behavior 在分配的内存范围之外写入。它现在可以工作,但不能依赖它来工作。附件J.2 中的C99 draft standard 未定义行为 说:

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

    注意3.4.3未定义的行为部分定义了第2段中的术语(强调我的):

    可能的未定义行为范围从完全忽略导致不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(无论是否发出诊断消息),终止翻译或执行(发出诊断消息)。

    【讨论】:

      【解决方案2】:

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

      例如,您的堆栈可能会向下增长。当您进行函数调用时,您可能会获得寄存器值、返回地址、参数值和其他放入堆栈的内容。然后,只有到那时,你的buf 的 6 个字节才会被分配。如果所有其他内容占用了 12 个字节,那么您可以向 buf 写入 18 个字符,并且仍然只触及 您 不应该更改但您的进程拥有的内存。由于您的进程拥有它,因此您不会获得非法内存访问,也不会崩溃。一旦超过 18 个字节,您很可能会进入进程不拥有的内存,并且会出现段错误并且游戏将启动。

      C 的原因是您只是有未定义的行为,并且发生了您甚至不应该尝试理解的奇怪事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多