Повреждение памяти / переупорядочение структуры в OSX + llvm / libStack Overflow

После получения кросс-платформенного проекта для компиляции у меня возникают самые странные ошибки в OSX. Программа падает по-разному (но иногда может выжить, чтобы показать, что это пользовательский интерфейс). Проходя через отладчик XCode, я вижу несколько мест, где значения подобъектов менять в зависимости от контекста. Это небольшая проблема у меня:

class third
{
public:
int some_data;
void do_something()
{
}

};

class second
{
public:
third * thirdPtr;

second()
: thirdPtr(nullptr)
{
thirdPtr = new third();
printf("second = 0x%X, third = 0x%X", this, thirdPtr);
}

};class first
{
second * secondInstance;
first()
: secondInstance(nullptr)
{
secondInstance = new second();
printf("second = 0x%X, third = 0x%X", secondInstance, secondInstance->thirdPtr);
// (maybe) crash
secondInstance->thirdPtr->do_something();

}

};

Проходя, я добавил точку наблюдения к третьему указателю, это пример вывода:

Watchpoint 1 hit:
old value: 0x00000001
new value: 0x00000000

Watchpoint 1 hit:
old value: 0x00000000
new value: 0x04821c34

И вот стандартный вывод программы:

second = 0x4821C20, third = 0x4821C34
second = 0x4821C20, third = 0x3404821C

Я никогда не видел ничего подобного. Очевидно, что структуры являются более сложными и используют наследование, но ничто другое не имеет доступа или записи в эти структуры при инициализации. У меня так много странных сбоев и проблем в моем исходном коде, поэтому я предполагаю, что этот сбой является проблемой в нескольких местах. Напоминаем, что исходный код долгое время работал безупречно на других платформах, и он дает сбой даже во внешнем библиотечном коде (я использую juce для проекта).

Сначала я подозревал, что оператор new является поддельным, но, похоже, что-то связано с составом объектов. Интересно, что две разные трети имеют сильное сходство.

Я действительно в растерянности, я готов заключить, что llvm переставляет расположение структур между компилируемыми модулями (классы / структуры находятся в отдельных файлах, конечно) … или что-то в этом роде. Я предполагаю, что я не прав — но кто-нибудь когда-либо испытывал что-то подобное?

——— редактировать ———-:

Поэтому я добавил этот код:
(внутри второго конструктора):

    {
thirdPtr = new third();
printf("second = 0x%X, third = 0x%X", this, thirdPtr);
printf("position = %d", offsetof(second, thirdPtr);
}

(внутри первого конструктора):

    {
secondInstance = new second();
printf("second = 0x%X, third = 0x%X", secondInstance, secondInstance->thirdPtr);
printf("position = %d", offsetof(second, thirdptr));

}

И это печатает …

13
16

Примечание: это вывод полных структур (т. Е. Не приведенных здесь примеров). НО: Структура структур на самом деле различается в зависимости от того, в каком модуле компиляции / перевода я нахожусь. Что, черт возьми, здесь происходит?

——— редактировать 2 ———:

Поэтому я решил проверить выравнивание, это может быть ключевой проблемой:

stdout изнутри второй конструктор:

second = 0x3649090, third = 0x36490A4
offset of third in second = 16
sizeof second = 232
align of third = 4, align of second = 4

стандартный вывод из первого конструктора:

second = 0x3649090, third = 0xA4036490
offset of second in third = 13
sizeof second = 226
align of third 1, align of second 1

Так что, похоже, выравнивание меняется в единицах перевода. Что я могу сделать, чтобы обеспечить соблюдение стандарта во всем проекте?

редактировать 3: мне удалось заставить его «работать», как в, он не падает сразу, применяя атрибут((упаковано)) во второй класс. Но это действительно не оставляет меня в безопасности, и почему я должен это делать? Существует ли глобальный параметр, который управляет этим параметром в единицах перевода?

—— редактировать 4: РЕШЕНИЕ —-

Включенный заголовок содержал несоответствующую директиву #pragma pack (которую поддерживает llvm) следующим образом:

    #ifdef __MSVC__
#pragma pack(push, 1)
#pragma warning(disable:4482)
#else
#pragma pack (push, 1)
#endif

....

#if defined(__MSVC__)
#pragma pack(pop)
#endif

Стек упаковки будет изменен любым компилятором, но будет восстановлен только при использовании компилятора msvc ++. Это оставило упаковку всего проекта до 1.

0

Решение

Стало очевидным, насколько важно сбросить упаковочный стек при работе с пользовательским выравниванием уплотнения конструкций.

Компилятор Visual Studio и внешний интерфейс clang для llvm поддерживают один и тот же синтаксис с использованием директив #pragma, которые можно изучить здесь:
http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx

В моем случае включенный заголовок содержал несоответствующую директиву #pragma pack примерно так:

    #ifdef __MSVC__
#pragma pack(push, 1)
#else
#pragma pack (push, 1)
#endif

....

#if defined(__MSVC__)
#pragma pack(pop)
#endif

Стек упаковки будет изменен любым компилятором, но будет восстановлен только при использовании компилятора msvc ++. Это оставило выравнивание упаковок блоков перевода, которые включали этот файл, в отличие от тех, которые этого не делали, даже если оба блока перевода видели одно и то же определение структуры. Для полноты вот (в моем случае) исправленные директивы #pragma:

    #if defined(__MSVC__) || defined (__LLVM__)
#pragma pack (push, 1)
#endif

#if defined(__MSVC__) || defined (__LLVM__)
#pragma pack(pop)
#endif
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]