15
votes

Many C/C++ compilers (including gcc and clang) have a feature called packed structures. It comes in handy for a number of reasons, but it has to be used with caution. One potential pitfall is that you use a pointer to a member of a struct as an argument of another function. Now that function is unaware of the unaligned pointer. Let me illustrate what I mean with some code:

#pragma pack(1)
typedef struct { int x; } uas;
#pragma pack()

void foo(int *f) {
  // some code using the value of *f
}
void bar(uas *b) {
  foo(&(b->x));
}

The alignment of int on a 32 bit machine is usually 4. The compiler now may generate code for foo() that may not work if f is not 4 byte aligned. This is the case on older ARM architectures.

Now struct uas and all members within have an alignment guarantee of 1. Clearly, passing the address of b->x to foo() is a bad idea.

GCC and clang have a compiler warning (-Wcast-align) which is triggered, for example, by casting char* to int*. Using pointers to members of packed structures, even though supported by both, doesn't seem to trigger this warning. I also tried -Wall and -Wextra, but they do not even include -Wcast-align.

My main question is whether GCC, clang, or any other compiler supporting packed structures have a warning that would be triggered by the particular example above. It seems, such a warning is mandatory if compilers support packed structures.

3
This is very close to this question, albeit more specific. The GCC bug report mentioned in that answer talks specifically about pointers, though.unwind
Well, it's sorta accepted/expected that, if you have such a packed struct/class, you pass only the start address and dereference in the target, so avoiding passing the address of an unaligned var. If devs do weird stuff, then weird stuff will happen.Martin James
Some humans make mistakes. Other humans don't know and basically accept whatever works on their machine as "correct". That's why we have programs that give us "hints" where the humans might have done bad things. Having a "hint" for this particular case really makes sense.Sven
Have you tried compiling it on an arch where unaligned access to integers is not permitted? On x86 it's not only permitted but not even slower these days (thanks to the cache).Andy Brown
I tried to cross-compile for ARM. I even tried -Weverything with clang.Sven

3 Answers

8
votes

clang has just added a new -Waddress-of-packed-member warning for this specific issue. See https://reviews.llvm.org/rL278483 and https://llvm.org/bugs/show_bug.cgi?id=22821 for details. It should appear in the 4.0 release of clang.

4
votes

gcc has just added the same warning (-Waddress-of-packed-member) in gcc-9. It is enabled by default when using -Wall

0
votes

consider following alignment for the typedef structure definition:

#pragma pack(1)
typedef struct { int x; } uas __attribute__ ((aligned (sizeof(uint32_t))));
#pragma pack()

this will notify compiler to make sure all allocations of the structure will be 4 bytes aligned.

the reference is here