Why doesn’t &(NULL->local) cause my program to crash?

This is a example code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct substruct {
    int integer1;
    unsigned char boolean1;
    unsigned char boolean2;

    char *ptr1;
    char *ptr2;
} substruct_t;

typedef struct tester {
    char *ptr1; //0x00
    char *ptr2; //0x08


    unsigned char boolean1; //0x10
    unsigned char boolean2; //0x11
    int integer1; //0x12

    // padding bypte 0x16 -> 0x18
    char *ptr3; //0x18
    // It is not pointer.
    substruct_t local; // 0x20

    char *ptr4;
} tester_t;


int main()
{
    tester_t *tester;
    tester = NULL;
    printf("0\n");
    substruct_t *localptr = &(tester->local);
    printf("1\n");
    // seg fault
    substruct_t test_local = tester->local;
    printf("2\n");
    substruct_t *test_local_ptr = &test_local;
    printf("3\n");

    // localptr = &(0x20); ???
    // void *voidptr = 0x20;
    // substruct_t *testptr = (substruct_t *)&(voidptr);
    // printf("4\n");

    return 0;
}

Why doesn’t the program die at &(tester->local) line?
I want to know why test->local causes a crash, but &(test->local) doesn’t.

This is the output result.

$ gcc -Wall -g -o asdf asdf.c
$ ./asdf
0
1
[1]    1777 segmentation fault  ./asdf

0, 1 print but 2 not print. seg fault at tester->local line.

  • As the offending lines of code don’t do anything, it’s not inconceivable that a compiler could optimize them away, eliminating the undefined behavior.

    – 

Both lines dereference a NULL pointer, and doing so triggers undefined behavior in your code.

With undefined behavior, there is no guarantee what your code will do. It might crash, it might print strange results, or it might (as in your case with the first line) appear to work properly. Additionally, making a seemingly unrelated code change, such as adding an unused local variable or a call to printf for debugging, can change how undefined behavior manifests.

Just because your code could crash doesn’t mean it will.

That being said, what’s probably happening is that the compiler looks at &(tester->local) and simply calculates the offset of the local member and adds that to the current value of tester without actually performing a dereference. But again, this is undefined behavior and there’s no guarantee of this.

Leave a Comment