pragma pack(push) без соответствующего pop приводит к разбиению стека
Я использовал #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 будет писать за кадром стека?
Я использую gcc v7.4.0 в Ubuntu 18.04.
/* 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
1 ответ
Поскольку pragma pack
влияет на макет экземпляров класса, ваша версия ofstream
не выглядит так же, как тот, который использовался для компиляции вашей стандартной библиотеки. Формально у вас есть нарушение ODR, что приводит к неопределенному поведению.
На практике функции из вашей среды выполнения C++ работают вслепую с данными с неправильным макетом, поэтому имеет смысл только фейерверк. В частности, ожидается разбиение стека, поскольку упакованный класс короче распакованного, поэтому запись в конец экземпляра переполняет пространствоmain
зарезервированный для него стек стека.