我在头文件中结构的开头使用了#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
堆栈帧。