在做看雪2020 KCTF秋季赛第3题 重返地球时,发现了一对奇怪函数:setjmp3、longjmp。不清楚它们是干什么的,上网搜索后明白了它们的用途,现简要记录下。
#include <setjmp.h>
int setjmp(jmp_buf env);
返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值的longjmp中的val值
void longjmp(jmp_buf env,int val);
调用此函数则返回到语句setjmp所在的地方,其中env 就是setjmp中的 env,而val 则是使setjmp的返回值变为val。第一个参数就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。
举例:
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second(void){
printf("second\n");// 打印
longjmp(buf,1); // 跳回setjmp的调用处 - 使得setjmp返回值为1
}
void first(void){
second();
printf("first\n"); // 不可能执行到此行
}
int main(){
if( ! setjmp(buf) ) {
first();// 进入此行前,setjmp返回0
}else{// 当longjmp跳转回,setjmp返回1,因此进入此行
printf("main\n");// 打印
}
return 0;
}
上述程序将输出:
second
main
虽然first()子程序被调用,"first"不可能被打印。"main"被打印,因为条件语句if (!setjmp(buf) )被执行第二次。
使用setjmp和longjmp要注意以下几点:
1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序:先调用setjmp函数,再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出
2. longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。
网友评论