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