没有相应 POP 的编译指示包(推送)会导致堆栈粉碎



我在头文件中结构的开头使用了#pragma pack(push, 2),但忘记了相应的#pragma pack(pop)。包含此头文件后,我添加了 fstream。在创建ofstream对象时,我看到堆栈粉碎。确切方案和代码的详细信息如下。

我正在学习一门C++课程,并为该项目编写了代码。我的程序由于堆栈粉碎而崩溃。我试图寻找任何明显的溢出错误,但找不到任何错误。我几乎更改了所有代码,使其类似于讲师提供的代码。唯一的区别是包含的头文件的顺序。我包含了我的头文件,后跟fstream而教师在顶部包含了fstream头文件。我仍然遇到同样的问题。所以我甚至改变了头文件的顺序,瞧,问题消失了。

由于这对我来说很奇怪,我试图在我的代码中本地化这个问题。
我在整个代码中插入了 print 语句,以查找发生堆栈粉碎的函数。

在找到函数时,我使用 gdb 来监视我的程序用来检查堆栈粉碎的金丝雀值。我在对象的构造函数中检测到堆栈粉碎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会影响类实例的布局,因此您的ofstream版本看起来与用于编译标准库的版本不同。从形式上讲,您有 ODR 违规,这会导致未定义的行为。

实际上,C++运行时的函数对布局错误的数据盲目操作,因此只有烟花接踵而至才有意义。由于打包类比解压缩的类短,因此写入实例末尾会溢出为其保留的空间main堆栈帧。

最新更新