I have the following C code:
#include <stdio.h>
#include <stdlib.h>
typedef struct num {
int a;
struct num *c;
} num;
void init_struct(num *n) {
num some_num = { 1 };
n->c = &some_num;
}
int main() {
num *n = malloc(sizeof(num));
init_struct(n);
printf("%d\n", (n->c)->a);
return 0;
}
From my understanding, the call to printf("%d\n", (n->c)->a)
should result in a segmentation fault, since it's accessing a memory that is freed already. But in fact, it returns 1.
My reasoning is as follows:
- When
init_struct
is called, it creates asome_num
struct with itsa
member set to 1, its address is assigned ton->c
, then it is freed. n->c
now keeps the address of a freed struct, calling(n->c)->a
should result in a segmentation fault.
Turns out it's not the case, but I don't know why.
I'm running this with gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
CodePudding user response:
Oh, it's freed all right. To quote Raymond Chen, "appearing to work is undefined behavior, but it's still undefined."
Accessing a pointer to what was a stack variable will not segfault, and is disgustingly likely to work in a toy example. Nothing actually checks that you access free stack. That would be too slow. So it just doesn't, and you get whatever was there last.
The value to be printed is being computed directly in main()
and in x64, the slot to which it will be pushed for the printf
call is already allocated at the top of main()
; thus nothing has the chance to overwrite the value. However, if the process were to receive a signal in between, the value will be stomped in the signal handler and there's nothing you can do about that.
CodePudding user response:
Just to demonstrate that this is Undefined Behavior I ran your code as is, and got your result = 1
then I ran this code
int main() {
num* n = malloc(sizeof(num));
init_struct(n);
fopen("not here", "r"); <<<<====
printf("%d\n", (n->c)->a);
return 0;
}
and got
-242574432
You got the worst kind of UB, it appeared to work fine, but it will fail in the middle of the busiest day of your most demanding customer