Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dereference variable address through null structure pointer, no segmentation fault

typedef struct {
    int a;
}stTemp_t;

int main()
{
stTemp_t *pstTemp = NULL;
int *p = &(pstTemp->a);       // <<----- supposedly de-ref NULL pointer

return 0;
}

The instruction pointed above, i thought should've caused a segmentation fault which it does not. I tried omitting the default compiler optimization by using "gcc -O0".

Naturally enough, if I replace that with int i = pstTemp->a, I get a seg-fault. I tried to run the above program throgh gdb to figure out what is going on & following is my observation -

(gdb) p pstTemp
$2 = (stTemp_t *) 0x0
(gdb) p pstTemp->a
Cannot access memory at address 0x0
(gdb) p &(pstTemp->a)
$3 = (int *) 0x0

here in $3, we can see that when i try to print &(pstTemp->a), it seems to be interpreted as an address hence being equivalent to int *p = NULL.

However my doubt is, shouldn't the statement (pstTemp->a) get evaluated before the & takes effect & cause a seg-fault anyways?

like image 505
Jitendra Avatar asked Dec 20 '22 01:12

Jitendra


2 Answers

Actually, it's not even the act of dereferencing the null pointer that's causing undefined behavior in your code.

When an address-of (&) and a dereference (* or ->) operation follow each other immediately, then they cancel each other and collapse into pointer arithmetic. Thus, the expression &pstTemp->a yields the address of a.

However, performing pointer arithmetic on a NULL pointer is undefined behavior. Since no actual dereferencing done (and the behavior is undefined anyways), it seems the compiler just didn't emit any apparently harmful code that would caused a segmentation fault.

Don't expect undefined behavior to result in any particular error. It's called undefined and not "guaranteed crash" for a reason.

like image 53
The Paramagnetic Croissant Avatar answered Apr 27 '23 02:04

The Paramagnetic Croissant


It's undefined behaviour.

It doesn't crash here, because there is no actual dereferencement, we only take the address of (pstTemp->b) which is actually the offset of the b field (most likely 4, depending on the size of int and the compiler).

Try this:

typedef struct {
    int a;
    int b;
} stTemp_t;

int main()
{
  stTemp_t *pstTemp = NULL;
  int *p = &(pstTemp->b);

  printf ("%p", p);
  return 0;
}

Te output will most likely be:

00000004

But

   printf ("%d", pstTemp->b);

will most likely crash.

like image 34
Jabberwocky Avatar answered Apr 27 '23 04:04

Jabberwocky