I ran into a nasty schrödinbug recently. While trying to load a file into a flat memory representation, the author had written code like this:
class Line final { public:
int stuff[3];
char* data;
}
//...
Line* line = /*...*/;
//Trying to treat line->data like an array. This is *wrong*.
line->data = reinterpret_cast<char*>(line) + 3*sizeof(int);
//...
line->data[0] = /*...*/
line->data[1] = /*...*/
//...
line->data[n] = /*...*/ //"line->data" changes because of this line!
So, what's happening is that the first lines of code essentially set line->data
equal to &line->data
. This is a mistake because any changes to values pointed to by line->data
could also change what line->data
itself is pointing to!
I found it curious then that it took so long for the problem to occur. My understanding is that, unless qualified with restrict
(or for g++/MSVC __restrict
) the compiler must assume that pointers are aliased. So if I set line->data[0]
to be something, then it will be visible to the next access, line->data[1]
, and will almost certainly be invalid. In the debugger, however, the change was not visible until much later, and the writes continued happily for a time.
I'm guessing the compiler (in this case MSVC 2013) didn't consider self-aliasing to be possible. Is that allowed?