这是家庭作业。我得到了一个 c++ 文件,该文件应该演示缓冲区溢出错误,我需要更正该错误。不幸的是,我无法重现开始时的错误。两个局部变量彼此紧挨着声明,大概是因为当字符数组的值太大时,溢出将进入下一个变量,现在将显示不正确。
这是给我的代码(删除了一些注释):
#include <iomanip>
#include <iostream>
int main()
{
std::cout << "Buffer Overflow Example" << std::endl;
const std::string account_number = "CharlieBrown42";
char user_input[20];
std::cout << "Enter a value: ";
std::cin >> user_input;
std::cout << "You entered: " << user_input << std::endl;
std::cout << "Account Number = " << account_number << std::endl;
}
但是,当我在提示符中输入超过 20 个字符时,它仍然会返回我输入的完整字符串,然后返回
account_number
的正确值。我的理解是我输入的额外字符应该渗入account_number
.
在项目属性下,我已经尝试关闭基本运行时检查(在 C/C++->代码生成下)并且我已经关闭了随机基地址(在链接器->高级下)。我是否需要更改其他一些设置才能产生更可预测的缓冲区溢出?
编译器可以做各种优化,也不能保证两个局部变量在堆栈上以确定的顺序排列。此外,
std::string
为其堆上的内容分配内存,除非使用小字符串优化。后者取决于操作系统和 CPU 架构(特别是 32 位或 64 位 CPU)。
正如 Alan Birtles 所提到的,自 C++20 以来,
operator<<
重载将看到您正在读取固定大小的数组,并且不会导致它越界写入。
编译器也可以决定没有任何东西可以合法地覆盖
const
字符串account_number
,所以它不能在堆栈上为它生成局部变量,而是将字符串存储在二进制文件的常量数据部分中。
实现此目的的一种方法是将缓冲区放在结构中并在其后放置一个“幻数”:
struct ProtectedBuffer
{
char buffer[20];
unsigned magicNumber = 1234;
bool overflow() {magicNumber != 1234;}
};
这样,缓冲区的任何溢出都会渗入可以检测到的固定幻数。