Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what exactly is the danger of an uninitialized pointer in C

I am trying get a handle on C as I work my way thru Jim Trevor's "Cyclone: A safe dialect of C" for a PL class. Trevor and his co-authors are trying to make a safe version of C, so they eliminate uninitialized pointers in their language. Googling around a bit on uninitialized pointers, it seems like un-initialized pointers point to random locations in memory. It seems like this alone makes them unsafe. If you reference an un-itilialized pointer, you jump to an unsafe part of memory. Period. But the way Trevor talks about them seems to imply that it is more complex. He cites the following code, and explains that when the function FrmGetObjectIndex dereferences f, it isn’t accessing a valid pointer, but rather an unpredictable address — whatever was on the stack when the space for f was allocated.

What does Trevor mean by "whatever was on the stack when the space for f was allocated"? Are "un-initialized" pointers initialized to random locations in memory by default? Or does their "random" behavior have to do with the memory allocated for these pointers getting filled with strange values (that are then referenced) because of unexpected behavior on the stack.

Form *f;
   switch (event->eType) {
   case frmOpenEvent:
   f = FrmGetActiveForm(); ...
   case ctlSelectEvent:
   i = FrmGetObjectIndex(f, field); ...
}
like image 964
bernie2436 Avatar asked Oct 16 '25 10:10

bernie2436


2 Answers

What does Trevor mean by "whatever was on the stack when the space for f was allocated"?

He means that in most assembly languages, separate instructions are used to reserve space on the stack and to write an initial value inside the newly reserved space. If a C program uses an uninitialized variable, the program will typically at run-time execute the instruction that reserves stack space but no instruction that sets it. When the pointer is used, it will literally contain the bit pattern that was on the stack before space was reserved. In the good cases this will be an invalid address. In the bad cases this will happen to be a valid address, and the effects will be unpredictable.

This is only a typical behavior. From the theoretical point of view, using an indeterminate value is undefined behavior. Much stranger things than simply accessing an invalid address or a valid one can happen (examples with uninitialized data (not addresses) used accidentally or purposely).


Here is the sort of dangers that a restricted subset of C such as Cyclone aims to prevent:

int a, *p;

int main(int c, char **v){
  int l, *lp, i;
  if (c & 1) 
    a = l + 1;      // danger
  if (c & 2)
    *lp = 3;        // danger
  if (c & 4)
    {
      p = &a;  
      for (i=0; i<=1; i++)
        {
          int block_local;
          *p = 4;   // danger
          p = &block_local;
        }
    }
}

In the last dangerous line, in practice, it is most likely that 4 will be written to variable block_local, but in reality, at the second iteration, p is indeterminate, the program is not supposed to access *p, and it is undefined behavior when it does.

like image 73
Pascal Cuoq Avatar answered Oct 19 '25 01:10

Pascal Cuoq


On modern OS's the danger is a core dump. On earlier systems without memory management and possibly memory mapped i/o to external HW the dangers are of completely different magnitude.

like image 38
Aki Suihkonen Avatar answered Oct 19 '25 00:10

Aki Suihkonen