Modifying a variable through a pointer of an incompatible type (other than unsigned char
) can lead to unpredictable results. This problem is often caused by a violation of aliasing rules. The C Standard, Section subclause 6.5, paragraph 7 [ISO/IEC 9899:2011], specifies those circumstances in which an object may or may not be aliased.
...
In this noncompliant example, a diagnostic is required because an object of type float
is incremented through a pointer to int
, ip
:
...
The programmer in this noncompliant code example is attempting to read from a different union member than the one most recently written to; this , which is known as type-punning:
Code Block | ||||
---|---|---|---|---|
| ||||
union a_union { int i; double d; }; int f() { a_union t; int *ip; t.d = 3.0; ip = &t.i; return *ip; } |
However, instead of reading directly from the union member, it assigns a pointer, ip
, to reference the integer value and returns the value referenced by the pointer. Unfortunately, this is a violation of the strict aliasing rules, and in this case, the compiler may determine that ip
refers to some value other than the value stored by t.i
and return a value other than the expected value.
...
In this noncompliant code example, access by taking the address, casting the resulting pointer, and dereferencing the result has undefined behavior , even if the cast uses a union
type:
Code Block | ||||
---|---|---|---|---|
| ||||
union a_union { int i; double d; }; int f() { double d = 3.0; return ((union a_union *) &d)->i; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
short a[2]; a[0]=0x1111; a[1]=0x1111; *(int *)a = 0x22222222; /* violationViolation of aliasing rules */ printf("%x %x\n", a[0], a[1]); |
...
In this example, a gadget
object is allocated, then realloc()
is called to create a widget
object using the memory from the gadget
object. While Although reusing memory to change types is acceptable, accessing the memory copied from the original object is undefined behavior.
...
This compliant solution reuses the memory from the gadget
object , but re-initializes reinitializes the memory to a consistent state before reading from it.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <string.h> struct gadget { int i; double d; char *p; }; struct widget { char *q; int j; double e; }; struct gadget *gp; struct widget *wp; gp = (struct gadget *)malloc(sizeof (struct gadget)); if (!gp) { /* Handle error */ } /* ... */ wp = (struct widget *)realloc(gp, sizeof(struct widget)); if (!wp) { free(gp); /* Handle error */ } memset(wp, 0, sizeof(struct widget)); if (wp->j == 12) { /* ... */ } |
...
[Acton 2006] | "Understanding Strict Aliasing" |
GCC Known Bugs | "C Bugs, Aliasing Issues while Casting to Incompatible Types" |
GCC Manual | |
[ISO/IEC 9899:2011] | Section Subclause 6.5, "Expressions" |
[Walfridsson 2003] | Aliasing, Pointer Casts and GCC 3.3 |
...