4
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?

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Can you please point me to the related chapter in the standard, preferably C11? I see nothing in §6.5.2.3,
@SouravGhosh I'm searching for the relevant part.
Yes, please let me know. Specifically, I'm interested in they cancel each other and collapse into pointer arithmetic part. I can see the example from footnote (102) in §6.5.3.2, but that is not quite the same. I'm interested. Is this indeed a pure C thing or something compiler specific?
@SouravGhosh that's not the same order, but given that "A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object" (6.5.2.3) and "if it [the operand of *] points to an object, the result is an lvalue designating the object", and a member of a structure or union must be an object (or a bitfield, which doesn't count here since its address cannot be taken), this means that the other direction is also true: &foo->bar is the same as &(*foo).bar, and…
@SouravGhosh for & followed by *, the standard already says "If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted" (6.5.3.2).
4

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.