I wrote a small demo program
#include <stdlib.h>
#include <stdio.h>
typedef struct tag_node {
struct tag_node *left, *right, *prev;
int value;
} node;
int main()
{
node *root_node = malloc(sizeof(node));
root_node->value = 1;
node **position = &root_node->right;
*position = malloc(sizeof(node));
(*position)->value = 2;
(*position)->prev = root_node;
printf("root node is %d, right node is %d\n",
root_node->value, root_node->right->value);
node **ptr = &(*position)->prev->prev->prev;
printf("This is fine\n");
return 0;
}
and compiled it with gcc -Wall -Wextra -g -O0 example.c -o example.
In my opinion the program must crash at the node **ptr = &(*position)->prev->prev->prev; line because:
*positionis theroot->rightaddress;(*position)->previs therootaddress;(*position)->prev->previs therootpreviousaddress, i.e., NULL;(*position)->prev->prev->previs NULL dereferencing, which must cause asegfaulterror.
Nevertheless the program feels great, prints "This is fine" and returns exit code 0.
Could someone please explain this black magic to me?
The line
is meaningless and can be eliminated by the optimization.
Interestingly, adding a line
after the line to make the line meaningfull also didn't invoke segmentation fault.
This looks like because we can read
(*position)->prev->prev(this meansroot_node->prev) and can calculate the address&(*position)->prev->prev->prevby just adding the offset of the memberprevto the value of(*position)->prev->prevwithout actually accessing(*position)->prev->prev->prev.Also note that
mallocdoesn't initialize the allocated buffer and the value of(*position)->prev->prevneed not beNULL.