2

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

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

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

在找到函数时,我使用 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

4

1 回答 1

1

由于pragma pack影响类实例的布局,您的版本ofstream看起来与用于编译标准库的版本不同。形式上,您违反了 ODR,这会导致未定义的行为。

实际上,C++ 运行时中的函数会盲目地对布局错误的数据进行操作,因此只有出现烟花才有意义。特别是堆栈粉碎是预期的,因为打包类比解包类短,因此写入实例末尾会溢出main为其保留的空间堆栈帧。

于 2019-10-02T08:33:38.263 回答