应该在 longjmp() 之后调用 free() 吗?
Should free() been called after longjmp()?
在这个简单的代码中,我应该注意默认情况下的内存释放以避免内存泄漏,还是我可以使用分配的内存? longjmp 是否也恢复内存分配?
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char* argv)
{
jmp_buf jmpbuf;
int *p=NULL;
switch(setjmp(jmpbuf)){
case 0:
p=(int *) malloc(10*sizeof(int));
printf("%p\n",p);
longjmp(jmpbuf,1);
break;
default:
printf("%p\n",p);
free(p);
}
return 0;
}
不,longjmp
不会恢复动态内存分配。
longjmp 将恢复变量 "on the stack" 的 值 (在本例中为 "p")。但是,此示例中存在两个问题:
- 在默认情况下,p 没有被赋值,释放它会出错。
- 如果示例显示 p 正在分配一个示例,内存泄漏仍然无法修复,因为 longjmp 对此无能为力。
longjmp()
不会 为您释放内存,因此您必须手动 free()
它。这是使用 setjmp()
/longjmp()
逃避深层调用堆栈的复杂性之一,因为您必须担心清理任何父函数使用的资源。请注意,在您的示例中,您 必须 将 p
声明为 volatile
(int *volatile p = NULL;
) to prevent it from potentially getting clobbered by longjmp()
, since it's modified after the setjmp()
call (see here 以获得解释)。
这是一个完全有效的程序,除了:
- 未将
p
声明为 volatile
和
- 声明
argv
为 char *
。
是的,如果在 longjmp()
之前分配了内存,则需要在 longjmp()
之后调用 free()
。
因为保证 setjmp
的 return 值在直接执行时将是 0
,我们可以确定内存 将是 通过 case 0
.
分配
并且,如果在 setjmp()
之后和调用 longjmp
之前需要更改局部变量,那么您需要将其声明为 volatile
以要求编译器不要优化和存储在寄存器中,但仅从堆栈到 store/load。
为什么?因为当 longjmp
加载保存的环境时,它会加载在直接 setjmp()
调用时保存的程序计数器、堆栈指针和寄存器中的值。如果编译器在 setjmp()
调用后优化变量并将其存储在寄存器中,则 longjmp
无法访问该值,因为它具有的是 在 时的寄存器值setjmp
打电话。所以我们要求编译器不要保存在寄存器中,而是只从堆栈中保存 save/load。由于 longjmp
有堆栈指针,我们从堆栈中获取可访问变量的最新值。
更新代码:
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
jmp_buf jmpbuf;
volatile int *p;
switch (setjmp(jmpbuf)) {
case 0:
p = malloc(10 * sizeof(int));
printf("p = %p\n", (void *)p);
longjmp(jmpbuf, 1);
break;
default:
printf("p = %p\n", (void *)p);
free((void *)p);
}
return 0;
}
在这个简单的代码中,我应该注意默认情况下的内存释放以避免内存泄漏,还是我可以使用分配的内存? longjmp 是否也恢复内存分配?
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char* argv)
{
jmp_buf jmpbuf;
int *p=NULL;
switch(setjmp(jmpbuf)){
case 0:
p=(int *) malloc(10*sizeof(int));
printf("%p\n",p);
longjmp(jmpbuf,1);
break;
default:
printf("%p\n",p);
free(p);
}
return 0;
}
不,longjmp
不会恢复动态内存分配。
longjmp 将恢复变量 "on the stack" 的 值 (在本例中为 "p")。但是,此示例中存在两个问题:
- 在默认情况下,p 没有被赋值,释放它会出错。
- 如果示例显示 p 正在分配一个示例,内存泄漏仍然无法修复,因为 longjmp 对此无能为力。
longjmp()
不会 为您释放内存,因此您必须手动 free()
它。这是使用 setjmp()
/longjmp()
逃避深层调用堆栈的复杂性之一,因为您必须担心清理任何父函数使用的资源。请注意,在您的示例中,您 必须 将 p
声明为 volatile
(int *volatile p = NULL;
) to prevent it from potentially getting clobbered by longjmp()
, since it's modified after the setjmp()
call (see here 以获得解释)。
这是一个完全有效的程序,除了:
- 未将
p
声明为volatile
和 - 声明
argv
为char *
。
是的,如果在 longjmp()
之前分配了内存,则需要在 longjmp()
之后调用 free()
。
因为保证 setjmp
的 return 值在直接执行时将是 0
,我们可以确定内存 将是 通过 case 0
.
并且,如果在 setjmp()
之后和调用 longjmp
之前需要更改局部变量,那么您需要将其声明为 volatile
以要求编译器不要优化和存储在寄存器中,但仅从堆栈到 store/load。
为什么?因为当 longjmp
加载保存的环境时,它会加载在直接 setjmp()
调用时保存的程序计数器、堆栈指针和寄存器中的值。如果编译器在 setjmp()
调用后优化变量并将其存储在寄存器中,则 longjmp
无法访问该值,因为它具有的是 在 时的寄存器值setjmp
打电话。所以我们要求编译器不要保存在寄存器中,而是只从堆栈中保存 save/load。由于 longjmp
有堆栈指针,我们从堆栈中获取可访问变量的最新值。
更新代码:
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
jmp_buf jmpbuf;
volatile int *p;
switch (setjmp(jmpbuf)) {
case 0:
p = malloc(10 * sizeof(int));
printf("p = %p\n", (void *)p);
longjmp(jmpbuf, 1);
break;
default:
printf("p = %p\n", (void *)p);
free((void *)p);
}
return 0;
}