Strict-aliasing in GCC
Ian Lance Taylor
iant@google.com
Tue Jun 1 06:49:00 GMT 2010
Jan Engelhardt <jengelh@medozas.de> writes:
> In http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43637 , I had a case
> where I apparently ran into strict-aliasing artifacts. As Richard
> Guenther points out in comment #2, I may have dereferenced through a
> pointer of wrong type. Yet I could not quite spot that yet as I added in
> comment #3.
> If somebody has a deeper insight into C's spots of undefinedness, a
> reply would be greatly appreciated.
#ifndef containerof
# define containerof(var, type, member) \
(type *)((char *)var - offsetof(type, member))
#endif
#define list_entry(ptr, type, member) containerof((ptr), type, member)
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) {&(name), &(name)}
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
...
#define list_for_each_entry(pos, head, member) \
for ((pos) = list_entry((head)->next, typeof(*(pos)), member); \
&(pos)->member != (void *)(head); \
(pos) = list_entry((pos)->member.next, typeof(*(pos)), member))
...
int main(void)
{
LIST_HEAD(clh);
LIST_HEAD(lh);
struct item *pos;
list_add_tail(&clh, &lh);
list_for_each_entry(pos, &clh, list)
This is going to expand into
for ((pos) = list_entry((&clh)->next, typeof(*(pos)), member);
==>
for ((pos) = containerof(((&clh)->next), typeof(*(pos)), member)
==>
for ((pos) = (typeof(*(pos)) *)((char *)((&clh)->next) - offsetof(...)
At this point you are starting with the field clh.next, which has type
"struct list_head", you are casting to to "char *", and you are
accessing it as type "struct item *". That is an aliasing violation.
Your comment discusses valid memory regions, but that is not the
issue. Standard C does not permit you to declare a field to have one
type and to access it as a different type; there are certain limited
exceptions which do not apply here.
Ian
More information about the Gcc-help
mailing list