为什么故意缓冲区溢出不会覆盖变量?

Why does intentional buffer overflow not overwrite variable?

这可能是一个愚蠢的问题,因为我很确定这是不可能的,但如果是的话,请随时告诉我我做错了什么。 所以我一直在试验缓冲区溢出以及内存在 C/C++ 中的一般工作方式,但我遇到了一些非常奇怪的事情。

char arr[16];
char tmp = 33;

strcpy(arr, "AAAAAAAAAA3211f11f2gg233h4h34h43AAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBB");

cout << tmp << endl;

这段代码出于某种原因产生了一个“!” (如果转换为 unsigned int 是 33),据我了解, strcpy 调用应该溢出 arr 并覆盖 tmp(或者甚至可能使程序崩溃,因为它是一个相当大的字符串),但它确实 none。

cout << arr[20] << endl;

此代码 returns 一个 "g" 尽管它在技术上是越界的。

您的代码正在调用未定义的行为,因为您正在写入未分配的内存。任何事情都可能发生,打印 'g',让你的盒子崩溃,否则你的冰箱可能会被搜查! :)

在给出实际答案之前,我需要承认语言律师的回答:未定义的行为是未定义的。您询问了未定义行为的意外结果,但是对于未定义行为的行为不应该有任何期望。

但实际的答案是典型架构上的堆栈向低地址增长。

所以实际的期望是溢出arr[]将从当前函数的入口处丢弃保存的寄存器(可能包括return地址),所以当这个函数尝试时会发生不好的事情至 return。

但是在结构上晚于 arr[] 在堆栈上分配的东西将位于较低的地址并且不会溢出。在最简单的未优化编译器行为中,tmparr 晚分配且低于 arr,因此是安全的。

tmp 是安全的原因带有足够的编译器假设,即预测 tmp 是安全的或者如果 tmp 不安全则感到惊讶是荒谬的。但是 tmp 在该代码中仍然比不安全更有可能。 (被丢弃的函数保存的寄存器,远远超过 "a bit more likely than not"。但即使是这样也不是你可以相信的必然发生的事情)。