I am trying get a handle on C and Cyclone as I work my way thru Jim Trevor’s “Cyclone: A safe dialect of C” for a PL class. Trevor gives this example of an unsafe go-to statement:
int z;
{ int x = 0xBAD; goto L; }
{ int *y = &z;
L: *y = 3; // Possible segfault
}
Trevor explains the safety issue in the above code as follows:
Many compilers stack allocate
the local variables of a block when it is entered, and
deallocate (pop) the storage when the block exits
(though this is not mandated by the C standard).
If the example is compiled in this way, then when
the program enters the first block, space for x is allocated on the stack, and is initialized with the value
0xBAD. The goto jumps into the middle of the second block, directly to the assignment to the contents
of the pointer y. Since y is the first (only) variable
declared in the second block, the assignment expects
y to be at the top of the stack. Unfortunately, that’s
exactly where x was allocated, so the program tries
to write to location 0xBAD, probably triggering a
segmentation fault.
I don’t understand why the go to statement is an issue here. It seems like the issue is unpredictable behavior from the un-initialized pointer Z. At the start of the second block, int * y be filled with the address of Z. Z is uninitialized so it would fill int* y with the bit pattern on the stack in the area of memory referenced by Z. I don’t understand why Trevor’s paper implies that Z and X somehow both reference 0xBAD. Wouldn’t C create a new stack frame for the first block (as Trevor describes): thus writing 0xBAD to a new frame in memory (and not the location in memory referenced by Z)?
goto Lbypasses the initialization ofy(ywill not be set to&z), hence the problem when assigning to who-knows-where-it’s-pointing*y.No. The pointer
&zis actually valid. Theintvaluezis uninitialized, but that does not matter since you never attempt to read it; you’re actually trying to overwrite it.That is the point.
goto Lbypasses that.I think Trevor is implying a second potential problem here, though I’m not sure how many compilers, if any, would actually exhibit it. When leaving the block with
goto, the stack pointer (e.g.ESPon x86) may theoretically not be decremented. By skipping the initialization ofy, the stack pointer may not be incremented either. So if the compiler refers to locals using the stack pointer (instead of a frame pointer, e.g.EBPon x86), such a compiler may theoretically mistakexfory, as ifint* y = 0xBADhad happened.