`pragma pack(push, 1)` падает в GCC 4.4.7. Возможна ошибка компилятора?

Я столкнулся с ошибкой, которая поставила меня в тупик. Я сузил его до проблемы с командой pragma pack в GCC (в частности, RHEL Linux, GCC v.4.4.7), которую можно воссоздать в небольшом примере, показанном ниже. Похоже, что в этом случае GCC вычисляет неправильное смещение, что проявится как сбой в цикле. Удаление пакета pragma также устраняет ошибку, но в реальном приложении это приведет к использованию большого количества дополнительных гигабайт памяти, что нежелательно.

В приведенном ниже примере вам нужно будет скомпилировать с включенной оптимизацией (O3), чтобы столкнуться с ошибкой. Я также предоставил пример элемента (cMagic) в структуре, который можно удалить, что изменит выравнивание структуры и предотвратит появление ошибки.

Я взглянул на сгенерированную сборку и считаю, что это может быть ошибка компилятора. Я пропустил что-то еще? Может ли кто-нибудь подтвердить эту ошибку или дать какие-либо сведения?

Crash.cpp:

/*  Platform Version Info:
 *     gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
 *     uname: 2.6.32-504.16.2.el6.x86_64 #1 SMP Tue Mar 10 17:01:00 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux
 *
 *  Compiling:
 *     Must use -O3 for compiling and linking
 *     CXX= g++ -g -O3 -fPIC -rdynamic -Wall -Wno-deprecated -DDEBUG
 *     CPP= g++ -g -O3 -fPIC -rdynamic -Wall -Wno-deprecated -DDEBUG
 *
 *  Notes:
 *     This appears to be an optimization and alignment issue.
 *     Getting rid of a byte in Place (cMagic) causes the program to complete successfully.
 *
 */


#include <stdlib.h>
#include <iostream>

using namespace std;

#pragma pack(push,1)  // Structures must be packed tightly
#define MAGICCONSTANT 17

struct Place {
   int iFoo;
   char cMagic;         // GCC doesn't like cMagic.  Disillusion it and everything is OK
   int aiArray[MAGICCONSTANT];
};


#pragma pack(pop)

int main(int argc, const char *argv[])
{
   Place *pPlace = new Place;   // Place must be on the heap... so new, calloc, malloc, etc

   for (int c = 0; (c < MAGICCONSTANT); c++) {
      pPlace->aiArray[c] = 0;
   }

   delete pPlace;

   cout << "Complete!" << endl;
   return 0;
}

Макетфайл:

CXX= g++ -g -O3 -fPIC -rdynamic -Wall -Wno-deprecated -DDEBUG
CPP= g++ -g -O3 -fPIC -rdynamic -Wall -Wno-deprecated -DDEBUG

OBJS=   Crash.o
SRCS=   Crash.cpp
TARG=   crash

debug:: ${TARG}

all:: ${TARG}

${TARG}: ${OBJS}
        ${CPP} -o ${TARG} ${OBJS} ${LDFLAGS} ${LIBS}

clean::
        rm -f ${TARG} ${OBJS} ${TARG}.core core

График дизассемблирования (сгенерированный ASM-код):

График разборки


person Scott 'scm6079'    schedule 27.07.2015    source источник
comment
Это старый компилятор... пробовали ли вы использовать более новую версию, чтобы увидеть, сохраняется ли ошибка?   -  person JorenHeit    schedule 28.07.2015
comment
Текущая (июль 2015 г.) версия GCC — 5.2; GCC 4.4 появился в 2009 году. Попробуйте скомпилировать свой код с помощью GCC 5.2 (которую вы можете скомпилировать из его выпущенного исходного кода).   -  person Basile Starynkevitch    schedule 28.07.2015
comment
Для справки, проблема заключается в выровненном SSE movdqa.. смещение, вероятно, в порядке. Я предполагаю, что оптимизатор думает, что массив выровнен, но упаковка смещает его.   -  person Jester    schedule 28.07.2015
comment
Действительно, автовекторизатор, похоже, векторизует цикл, но делает это плохо. Отключение, вероятно, устранило бы сбой.   -  person Sebastian Redl    schedule 28.07.2015
comment
GCC 5.2 оптимизирует выходной цикл, поскольку он не используется. Добавляя volatile, он использует развернутую последовательность инструкций MOV, которые снова не восприимчивы. Увеличение MAGICCONSTANT до 129 создает цикл, но все еще с инструкциями MOV, поэтому проблема не возникает.   -  person Jester    schedule 28.07.2015
comment
@Jester Спасибо, это очень ценный отзыв. Код предназначен для корпоративного клиента, привязанного к версиям RHEL, поэтому я не уверен, что смогу обновить основные версии GCC. Я начну исследовать дальше.   -  person Scott 'scm6079'    schedule 28.07.2015


Ответы (1)


Посмотрите на использование __attribute__ ((packed)); вместо #pragma pack(1). IIRC, эта версия GCC обрабатывает это немного по-другому.

person Krista Wolffe    schedule 28.07.2015
comment
Кажется, это решило проблему в этом случае, хотя я не уверен, что это имеет тот же эффект, что и #pragma. Из документов этот атрибут, прикрепленный к определению типа enum, struct или union, указывает, что для представления типа используется минимально необходимая память. - person Scott 'scm6079'; 28.07.2015
comment
Хорошая точка зрения. Мне достаточно любопытно, чтобы позже попробовать запустить его через дизассемблер и посмотреть, что изменилось. - person Krista Wolffe; 28.07.2015