函数 return 后未释放 C 自动变量
C auto variable isn't freed after function return
我有以下 C 代码:
#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;
}
根据我的理解,对 printf("%d\n", (n->c)->a)
的调用应该会导致分段错误,因为它正在访问已经释放的内存。但实际上,它 returns 1.
我的推理如下:
- 当
init_struct
被调用时,它创建一个some_num
结构,其a
成员设置为1,它的地址分配给n->c
,然后它被释放.
n->c
现在保留已释放结构的地址,调用 (n->c)->a
会导致分段错误。
事实并非如此,但我不知道为什么。
我运行这个和gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
哦,解脱好了。引用 Raymond Chen 的话,“看似工作是未定义的行为,但它仍然是未定义的。”
访问一个指向堆栈变量的指针不会发生段错误,而且很可能在玩具示例中工作。实际上并没有检查您是否访问了空闲堆栈。那太慢了。所以它只是没有,你得到了最后的东西。
要打印的值直接在 main()
中计算,在 x64 中,它将被推送到 printf
调用的槽已经分配在 [=10 的顶部=];因此没有任何机会覆盖该值。但是,如果进程在此期间接收到信号,则该值将在信号处理程序中被踩踏,您对此无能为力。
只是为了证明这是未定义的行为我 运行 你的代码是这样的,得到你的结果 = 1
然后我运行这个代码
int main() {
num* n = malloc(sizeof(num));
init_struct(n);
fopen("not here", "r"); <<<<====
printf("%d\n", (n->c)->a);
return 0;
}
得到了
-242574432
你得到了最糟糕的 UB,它看起来工作正常,但它会在你最苛刻的客户最繁忙的一天中失败
我有以下 C 代码:
#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;
}
根据我的理解,对 printf("%d\n", (n->c)->a)
的调用应该会导致分段错误,因为它正在访问已经释放的内存。但实际上,它 returns 1.
我的推理如下:
- 当
init_struct
被调用时,它创建一个some_num
结构,其a
成员设置为1,它的地址分配给n->c
,然后它被释放. n->c
现在保留已释放结构的地址,调用(n->c)->a
会导致分段错误。
事实并非如此,但我不知道为什么。
我运行这个和gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
哦,解脱好了。引用 Raymond Chen 的话,“看似工作是未定义的行为,但它仍然是未定义的。”
访问一个指向堆栈变量的指针不会发生段错误,而且很可能在玩具示例中工作。实际上并没有检查您是否访问了空闲堆栈。那太慢了。所以它只是没有,你得到了最后的东西。
要打印的值直接在 main()
中计算,在 x64 中,它将被推送到 printf
调用的槽已经分配在 [=10 的顶部=];因此没有任何机会覆盖该值。但是,如果进程在此期间接收到信号,则该值将在信号处理程序中被踩踏,您对此无能为力。
只是为了证明这是未定义的行为我 运行 你的代码是这样的,得到你的结果 = 1
然后我运行这个代码
int main() {
num* n = malloc(sizeof(num));
init_struct(n);
fopen("not here", "r"); <<<<====
printf("%d\n", (n->c)->a);
return 0;
}
得到了
-242574432
你得到了最糟糕的 UB,它看起来工作正常,但它会在你最苛刻的客户最繁忙的一天中失败