没有相应 pop 的 pragma pack(push) 会导致堆栈粉碎
pragma pack(push) without corresponding pop leads to stack smashing
我在头文件中的结构开头使用了 #pragma pack(push, 2)
,但忘记了相应的 #pragma pack(pop)
。包含这个头文件后,我包含了 fstream。在创建 ofstream
对象时,我看到堆栈崩溃。具体场景和代码详情如下
我正在学习 C++ 课程并为该项目编写了代码。由于堆栈粉碎,我的程序崩溃了。我试图寻找任何明显的溢出错误,但找不到。我更改了几乎所有代码以类似于讲师提供的代码。唯一的区别是包含的头文件的顺序。我包含了我的头文件,后面跟着 fstream
,而讲师在顶部包含了 fstream
头文件。我仍然遇到同样的问题。所以我什至更改了头文件的顺序,瞧,问题消失了。
因为这对我来说很奇怪,所以我尝试在我的代码中定位问题。
我在整个代码中插入了打印语句,以找到发生堆栈粉碎的函数。
找到函数后,我使用 gdb 设置监视我的程序使用的 canary 值来检查堆栈粉碎。我在 ofstream
对象的构造函数中检测到堆栈粉碎。
此时我知道 fstream
之前包含的一些头文件干扰了它。所以现在我检查了我所有的头文件是否有任何愚蠢的错误,发现一个结构前面有 #pragma pack(push, 2)
但后面没有相应的 #pragma pack(pop)
。这个结构将被写成一个二进制文件。更正此问题已解决。
由于整个项目无关紧要,我用一个简单的代码片段重现了这个问题。虽然问题解决了,但是我想知道为什么会这样。我知道 pragma pack
指令用于防止编译器在结构中插入填充,因为必须将结构写入二进制文件。省略结构末尾的 pack(pop)
,对所有后续头文件使用相同的结构。但这会导致 ofstream 构造函数写入堆栈帧吗?
我在 Ubuntu 18.04.
上使用 gcc v7.4.0
/* code.cpp */
#include "header.h"
#include <fstream>
using namespace std;
int main(){
ofstream fout;
fout.open("file.ext", ios::out|ios::binary);
fout.close();
return 0;
}
头文件
#ifndef HEADER_H_
#define HEADER_H_
#pragma pack(push, 2)
struct something{
int a;
};
//#pragma pack(pop)
//Uncommenting the above line solves the problem
#endif
由于 pragma pack
影响 class 实例的布局,您的 ofstream
版本看起来与用于编译标准库的版本不同。正式地,您违反了 ODR,这会导致未定义的行为。
实际上,您的 C++ 运行时中的函数盲目地对布局错误的数据进行操作,因此随之而来的烟火才有意义。由于打包的 class 比未打包的更短,因此堆栈粉碎尤其是预期的,因此写入实例的末尾会溢出为它保留的 space main
的堆栈帧。
我在头文件中的结构开头使用了 #pragma pack(push, 2)
,但忘记了相应的 #pragma pack(pop)
。包含这个头文件后,我包含了 fstream。在创建 ofstream
对象时,我看到堆栈崩溃。具体场景和代码详情如下
我正在学习 C++ 课程并为该项目编写了代码。由于堆栈粉碎,我的程序崩溃了。我试图寻找任何明显的溢出错误,但找不到。我更改了几乎所有代码以类似于讲师提供的代码。唯一的区别是包含的头文件的顺序。我包含了我的头文件,后面跟着 fstream
,而讲师在顶部包含了 fstream
头文件。我仍然遇到同样的问题。所以我什至更改了头文件的顺序,瞧,问题消失了。
因为这对我来说很奇怪,所以我尝试在我的代码中定位问题。
我在整个代码中插入了打印语句,以找到发生堆栈粉碎的函数。
找到函数后,我使用 gdb 设置监视我的程序使用的 canary 值来检查堆栈粉碎。我在 ofstream
对象的构造函数中检测到堆栈粉碎。
此时我知道 fstream
之前包含的一些头文件干扰了它。所以现在我检查了我所有的头文件是否有任何愚蠢的错误,发现一个结构前面有 #pragma pack(push, 2)
但后面没有相应的 #pragma pack(pop)
。这个结构将被写成一个二进制文件。更正此问题已解决。
由于整个项目无关紧要,我用一个简单的代码片段重现了这个问题。虽然问题解决了,但是我想知道为什么会这样。我知道 pragma pack
指令用于防止编译器在结构中插入填充,因为必须将结构写入二进制文件。省略结构末尾的 pack(pop)
,对所有后续头文件使用相同的结构。但这会导致 ofstream 构造函数写入堆栈帧吗?
我在 Ubuntu 18.04.
上使用 gcc v7.4.0/* code.cpp */
#include "header.h"
#include <fstream>
using namespace std;
int main(){
ofstream fout;
fout.open("file.ext", ios::out|ios::binary);
fout.close();
return 0;
}
头文件
#ifndef HEADER_H_
#define HEADER_H_
#pragma pack(push, 2)
struct something{
int a;
};
//#pragma pack(pop)
//Uncommenting the above line solves the problem
#endif
由于 pragma pack
影响 class 实例的布局,您的 ofstream
版本看起来与用于编译标准库的版本不同。正式地,您违反了 ODR,这会导致未定义的行为。
实际上,您的 C++ 运行时中的函数盲目地对布局错误的数据进行操作,因此随之而来的烟火才有意义。由于打包的 class 比未打包的更短,因此堆栈粉碎尤其是预期的,因此写入实例的末尾会溢出为它保留的 space main
的堆栈帧。