GCC #pragma pack bug

#pragma pack is accepted by many C/C++ compilers as the de facto standard grammar to handle alignment of variables.

However there is an old bug in GCC, reported many times, the first of which was in 2002, still not fixed now.
#include <cstdio>
using namespace std;

#pragma pack(1)
template <typename T>
struct A {
    char a;
    int b;
};
A<int> x;
#pragma pack(2)
A<char> y;
#pragma pack(4)
A<short> z;

int main()
{
    printf ("%d %d %d\n", sizeof x,sizeof y,sizeof z);
    return 0;
}

This gives 5 6 8 instead of 5 5 5 as we may expect. (VC++ and ICC both give the more reasonable 5 5 5.)

This example is not very bad. Even worse is, that this bug can damage programs that use STL. Here is an example:

a.cpp:
#include <cstdio>
#include <map>
using namespace std;

#pragma pack(1)
void foo (const map<short,const char*> &x)
{
    for (map<short,const char*>::const_iterator it=x.begin();
            it!=x.end(); ++it)
        printf ("%d %s\n", it->first, it->second);
}

b.cpp:
#include <map>
using namespace std;

void foo (const map<short,const char *> &);

int main()
{
    map<short, const char *> x;
    x[0] = "Hello";
    x[1] = "World";
    foo (x);
}

Compile a.cpp and b.cpp separately and link them together. This program segfaults if compiled with GCC, but works well with ICC or VC++.

In conclusion, for better portability and/or reliability, never use #pragma pack unless absolutely necessary. If really unavoidable, always push and pop immediately before and after the structure definition. (If the program is intended to be compiled by GCC/ICC only, it is better to use the more reliable GCC-specific __attribute__((__packed__)).)

PS. It seems Sun CC (shipped with Solaris) also has this bug. It fails for the first example here, but for the second it works well. I don't know how manages to align pair<short,const char *> correctly...

No comments:

Post a Comment