setjmp()/longjmp()

AI Agent技术实战:基于豆包搜索API构建养生谣言识别系统 AI Agent(人工智能代理)作为能够自主感知环境、进行推理决策并执行行动的智能系统,其核心原理在于结合自主性、反应性、主动性和社交能力等特性。在技术价值层面,AI Agent通过模块化的Skill机制实现特定任务的能力单元化,每个Skill专注于明确领域并具备清晰的输入输出规范,这种设计让系统具备了良好的可扩展性。结合豆包搜索API提供的信息检索能力,AI Agent能够在养生健康等应用场景中实现权威信息的实时获取与智能分析。本文以养生谣言识别为例,详细展示了如何通过Python生态构建具备谣言识别、信 阅读详情

setjmp()/longjmp()

Setjmp() and longjmp() are subroutines that let you perform complex flow-of-control in C/Unix.

One of the keys to understanding setjmp() and longjmp() is to understand machine layout, as described in the assembler and malloc lectures of the past few weeks. The state of a program depends completely on the contents of its memory (i.e. the code, globals, heap, and stack), and the contents of its registers. The contents of the registers includes the stack pointer (sp ), frame pointer (fp ), and program counter (pc ). What setjmp() does is save the contents of the registers so that longjmp() can restore them later. In this way, longjmp() ``returns'' to the state of the program when setjmp() was called.

Specifically:

#include < setjmp.h >
int setjmp(jmp_buf env);

This says to save the current state of the registers into env . If you look in /usr/include/setjmp.h , you'll see that jmp_buf is defined as:

#define _JBLEN  9
typedef struct { int _jb[_JBLEN + 1]; } jmp_buf[1];

This is an irritating way of saying that jmp_buf is an array of _JBLEN+1 integers.

So, when you call setjmp() , you pass it the address of an array of integers, and it stores the value of the registers in that array. Setjmp() returns 0 when you call it in this way.

longjmp(jmp_buf env, int val);

Longjmp() resets the registers to the values saved in env . This includes the sp , fp and pc . What this means is that longjmp() doesn't return. Instead, when you call it, you return as if you have just called the setjmp() call that saved env . This is because the pc is restored along with the other registers. Setjmp() returns the val argument of longjmp() , which is not allowed to be zero (read the man page). Thus, you know when setjmp() returns a non-zero value that longjmp() was called, and is returning to setjmp() .

As an example, look at the following code (in sj1.c ):




When we run this, we get:

UNIX> sj1
i = 0
i = 2
UNIX>

So, first, we call setjmp() , and it returns 0. Then we call longjmp() with a value of 2, which causes the code to return from setjmp() with a value of 2. That value is printed out, and the code exits.

Setjmp() and longjmp() are usually used so that if an error is detected within a long string of procedure calls, the error may be dealt with gracefully by a high-level call. For example, look at sj2.c . It looks to be complicated, but really isn't. What happens is that there is a complicated series of procedure calls -- proc_1 through proc_4 . If proc_4 's argument is zero, then it flags the error by calling longjmp() . Otherwise, things proceed normally. As you can see, if you call sj2 with all positive arguments, then everything is ok. However, if you call it with all zeros, it will make the longjmp() call, and flag an error:

UNIX> sj2 1 2 3 4
proc_1(1, 2, 3, 4) = 4
UNIX> sj2 0 0 0 0
Error -- bad value of i (0), j (0), k (0), l (0)
UNIX>

Now, setjmp() saves all the registers, including the sp and fp . What this means is that if you return from a procedure that calls setjmp() , then the env buffer of that setjmp() will no longer be valid. Why? Because that env buffer contains the sp and fp of the calling procedure. If that procedure returns, then when you restore the sp and fp , the stack will be in a different state than before, and you will have an error. For example, look at sj3.c

.

When we execute it, we get the following:

UNIX> sj3
Setjmp() returned -- i = 0
s = Jim
In B: i=3. Calling longjmp(env, i)
Setjmp() returned -- i = 3
Segmentation fault (core dumped)
UNIX>

So, exactly what is happening? When the main() routine is first called, the stack looks as follows:

              Stack        
|----------------|
| |
| |
| |
| |
| |
| | <-------- sp
| env[0] |
| env[1] |
| env[2] | pc = main
| env[3] |
| .... |
| env[8] |
| other stuff | <------- fp
|--------------- |

Now, main() calls a() . First it pushes the arguments on the stack in reverse order, and then jsr is called, which pushes the return pc on the stack, and the old fp . The fp and sp are changed to make an empty stack frame for a() :

                                     Stack        
|----------------|
| |
| | <--------- sp, fp
/------------- | old fp in main |
| | old pc in main |
| "Jim" <--- | s = "Jim" |
| /--- | pointer to env |
| /--> | env[0] |
| | env[1] |
| | env[2] | pc = a
| | env[3] |
| | .... |
| | env[8] |
/------------> | other stuff |
|--------------- |

The first thing that a() does is allocate room its local variable i:

                                     Stack        
|----------------|
| | <--------- sp
| i | <--------- fp
/------------- | old fp in main |
| | old pc in main |
| "Jim" <--- | s = "Jim" |
| /--- | pointer to env |
| /--> | env[0] |
| | env[1] |
| | env[2] | pc = a
| | env[3] |
| | .... |
| | env[8] |
/------------> | other stuff |
|--------------- |

Then it calls setjmp() . This saves the current state of the registers. In other words, it saves the current values of sp , fp , and pc . Now, a() prints "i = 0 ", and "s = Jim ", and then returns to main() . Now the stack looks as before, except that env is initialized to the state of the machine when a() was called:

                                     Stack        
|----------------|
| |
| |
| |
| |
| |
| | <----------- sp
| env[0] |
| env[1] |
| env[2] | pc = main
| env[3] |
| .... |
| env[8] |
| other stuff | <------------ fp
|--------------- |

Now, main() calls b() , and the stack looks as follows:

                                     Stack        
|----------------|
| |
| | <--------- sp, fp
/------------- | old fp in main |
| | old pc in main |
| | i = 3 |
| /--- | pointer to env |
| /--> | env[0] |
| | env[1] |
| | env[2] | pc = b
| | env[3] |
| | .... |
| | env[8] |
/------------> | other stuff |
|--------------- |

Then longjmp() is called. The registers are restored to their values when a() called setjmp() , and the pc returns from setjmp() in a() . However, the values in the stack are the same as they were for b()

:

                                     Stack        
|----------------|
| | <--------- sp
| i = 2 | <--------- fp
/------------- | old fp in main |
| | old pc in main |
| | s?? = 3 |
| /--- | pointer to env |
| /--> | env[0] |
| | env[1] |
| | env[2] | pc = a
| | env[3] |
| | .... |
| | env[8] |
/------------> | other stuff |
|--------------- |

You should see the problem. The stack is in a bad state. In particular, a() expects there to be a (char *) where s is, and instead, there is the integer value 3. Thus, when it tries to print out s , it tries to find a string at memory location 3, and dumps core.

This is a very common bug with setjmp() and longjmp() -- to use them properly, you CANNOT RETURN FROM THE PROCEDURE THAT CALLS setjmp() . As you can see, this bug is subtle -- the stack frame for b() looks a lot like the stack frame for a() , and thus this bug might slip by unnoticed for a while.


Setjmp() and signals

One of the nice things about setjmp() and longjmp() is that you can longjmp() out of a signal handler, and back into your program. This lets you catch those signals again.

Look at sh4.c :

Note that this program longjmps out of alarm_handler after 8 seconds have passed, and then prints "Gave up ". Be sure you can trace through this.


png.c

Ok -- in the program

Look at png.c (which stands for "prime number generator"), there is some really cool stuff going on. Copy it and run it (you'll have to exit with CNTL-C ), and then see if you can figure out what's going on. Note that this program may seg-fault. Can you figure out why? Unfortunately, I will not have time to go over this program, but it is a good exercise to see if you can understand it.

Obviously, you'd do better to use threads to implement something like this.

【系统架构设计师】论文模板样例:论软件系统架构风格 本人于年月参与项目,该系统为*,在该项目组中我担任系统架构师岗位,主要负责系统整体架构设计。本文以该车联网项目为例,主要讨论了软件架构风格在该项目中的具体应用。底层架构风格我们采用了虚拟机风格中的解释器,因该公交共有几十种不同的数据协议,使用解释器风格可以满足整车数据协议兼容性需求;中间层关于应用层的数据流转采用了独立构件风格中的隐式调用,以减低系统间耦合度、简化软件架构,提高可修改性方面的架构属性;应用系统层采用了B/S的架构风格,统一解决公交行业性难题“实施推广难、维护难”问题。 阅读详情

相关推荐

RK3568+XS9922B+Android11双模视频输入:CVBS与AHD兼容驱动开发实战

本文详细介绍了基于RK3568平台和XS9922B解码芯片,在Android11系统上开发支持CVBS与AHD双模视频输入的兼容驱动实战。内容涵盖硬件选型、内核驱动框架分析、双模信号自动识别与配置、视频通道切换实现及图像质量优化等关键技术点,为车载监控等需要兼容新旧摄像头的项目提供完整解决方案。

js777的博客 379

setjmp()/longjmp()的使用方法

setjmp和longjmp.为了让你实现复杂的流控制,程序在系统里面运行完全依靠内存(代码段,全局段,堆存储器,栈存储器)和寄存器的内容(栈指针,基地址,计数器),setjmp保存当前的寄存器里面的内容,longjmp是恢复这些内容.longjmp返回setjmp程序当前的状态 先看一个例子: #include <csetjmp> #include <cstdio&g...

weixin_34128534的博客 216

保姆级教程:手把手教你从NASA Earthdata下载ASTER L2地表温度数据(附shp文件拖拽技巧)

本文提供了一份详细的NASA Earthdata平台ASTER L2地表温度数据下载教程,涵盖账号注册、数据筛选、shp文件拖拽技巧及质量检查等关键步骤。特别适合遥感领域初学者,帮助快速掌握高效获取ASTER L2T数据的方法,适用于城市热岛效应和农业监测等研究。

weixin_30736301的博客 470

setjmp()/longjmp()的使用方法和场合

setjmp和longjmp.为了让你实现复杂的流控制,程序在系统里面运行完全依靠内存(代码段,全局段,堆存储器,栈存储器)和寄存器的内容(栈指针,基地址,计数器),setjmp保存当前的寄存器里面的内容,longjmp是恢复这些内容.longjmp返回setjmp程序当前的状态. #include int setjmp(jmp_buf env); 保存当前寄存器的状态到env这个结构

bytxl的专栏 1105

将ue4程序嵌入qt界面显示

需求:将ue4程序嵌入qt界面显示 思路:通过使用 windowsAPI 对ue4窗口进行设置跟随qt界面以及活动窗口时的位置层序设置

weixin_44342705的博客 5844

PC微信逆向) 读取内存联系人链表

首先从一些网络上搜索到的信息可以得出联系人列表是保存在内存里的,并且是全局变量不会被释放,所以我们可以通过搜索某个联系人的信息来定位

Qwertyuiop2016的博客 2919

C中的信号处理和函数setjmp()/longjmp()的用法

函数setjmp()的行为:      直接调用,将所有与当前处理器相关的信息(比如指令指针的内容、运行时栈指针等)保存到jmp_buf中去并返回0,表现的像一个普通函数。      如果使用同一个jmp_buf调用longjmp(),则函数返回时又回到了刚刚从setjmp()返回的地方。这一次函数的返回值是调用longjmp()时所使用的第二个参数。注意,第二个参数不能为零。如果为零,则se

hustmsencyyq的专栏 403

AUTOSAR进阶图解==>AUTOSAR_SWS_COM

AUTOSAR COM模块是AUTOSAR通信堆栈的核心组件,提供信号导向的通信服务。该模块位于通信服务层,连接RTE与PDU Router,主要功能包括信号封装/提取、传输模式管理、信号路由、超时监控和字节序转换等。COM模块架构分为应用层、通信服务层和通信抽象层,包含信号管理、I-PDU处理、传输模式管理等组件。其配置结构包括顶层容器、I-PDU组、I-PDU和信号等多层次配置对象,支持丰富的参数设置。模块采用严格的状态管理机制,包括模块状态和I-PDU组状态转换,确保通信可靠性。

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 1243

c++异常处理例子分析——有关setjmp()/longjmp()

/*  * nonlocal.cpp  *  *  Created on: 2013-5-30  *      Author: msm  */ #include #include using namespace std; class Rainbow{ public: Rainbow(){cout ~Rainbow(){cout }; jmp_buf

777

使用 MATLAB/Simulink 构建一个电机-液压联合控制系统的仿真模型

本文详细介绍了基于Simulink的电机与液压执行机构联合控制系统建模方法。通过7个步骤,系统讲解了从创建项目、搭建PMSM电机模型、建立逆变器与矢量控制模块,到构建液压泵和执行机构模型的完整过程。重点展示了如何设置关键参数、添加测量反馈模块,并提供了实用的代码片段。教程还包含仿真运行流程、结果分析指标及进阶建议,帮助读者掌握多物理场耦合系统建模的核心技术。该方法适用于机电液一体化系统设计,为工程实践提供有效参考。

amy_mhd的博客 613

SAP 清账凭证 完整生成逻辑(超详细原理 + 底层规则 + 分录逻辑 + 互清特殊规则)

【SAP清账凭证核心逻辑摘要】(149字) SAP清账凭证生成遵循两大类型:1)资金往来对冲型(如F-32/F-44互清),强制生成含完整借贷分录的独立凭证,通过AUGDT/AUGBL字段绑定未清项,典型场景如应收冲应付(借:应付账款 贷:应收账款);2)纯核销型(如F.13自动清账),仅标记行项目状态不产生实际分录。关键规则:①仅未清项管理科目可清账;②互清必须配置主数据关联;③差额清账自动补差(折扣/汇差);④原始凭证永不修改,仅更新BSIK/BSAD等表状态。清账凭证均保留可追溯性,支持FBRA重置还

金牌架构师 542

Linux C 异常处理:非局部goto jmp_buf/setjmp()/longjmp()

一、代码         #include         jmp_buf、setjmp()、longjmp() #include #include //#include //jmp_buf、setjmp()、longjmp() // jmp_buf j; void raise_exception(void) { printf("before longjmp()

kanguolaikanguolaik的专栏 1165

Coze智能体实战:接口需求分析和接口调试

AI智能体的需求:能根据接口文档提取接口信息以及设计接口测试点,并进行接口调试返回接口测试结果。

十二测试录 282

【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现

一、转移表 二、回调函数是什么? 三、qsort函数细解 3.1 类比冒泡排序? 3.2 qosrt函数超详解 3.2.1qsort函数排序整型数据 3.2.2 使⽤qsort排序结构数据 四、 qsort函数的模拟实现 4.1 模拟qsort整形数据 4.2 模拟`qsort`排序结构数据

a_sen的博客 1629

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C++编程思想 第2卷 第1章 异常处理 传统的错误处理

使用assert()的意图是:用于开发阶段的调试,通过宏定义语句#define NDEBUG使其在最终发行的软件产品中失效 require.h中定义的函数对于一些小的程序来说已经足够了,但是对于更 复杂的应用则应当采用更加完善的错误处理代码 当确切地知道应该做什么的时候,错误处理变成非常简单明了,因为在 语境中已经知道了所有必要的信息 当在某个语境中不能得到足够的信息,问题就出现了,这是需要...

eyetired的博客 165

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Linux_C编程—信号处理函数的返回

文章目录信号处理函数执行完怎么办setjmp()/longjmp()sigsetjmp()/siglongjmp() 信号处理函数执行完怎么办 一般来讲,信号处理函数执行完毕都会正常返回,也可以调用其他函数返回到程序的主函数中。这里总结一下信号处理函数执行完毕后跳转到主函数中指定的位置的操作(有点类似goto语句,但goto不支持函数间的跳转,只能在一个函数中跳转),主要是通过俩对函数来实现的: ...

肥宅快乐博客 1398

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++中的异常(exception)

1.简介   异常是由语言提供的运行时刻错误处理的一种方式。提到错误处理,即使不提到异常,你大概也已经有了丰富的经验,但是为了可以清楚的看到异常的好处,我们还是不妨来回顾一下常用的以及不常用的错误处理方式。 1.1 常用的错误处理方式   返回值。我们常用函数的返回值来标志成功或者失败,甚至是失败的原因。但是这种做法最大的问题是如果调用者不主动检查返回值也是可以被编译器接受的,你

SzMing 1064

C++笔记 第六十三课 C语言异常处理---狄泰学院

如果在阅读过程中发现有错误,望评论指正,希望大家一起学习,一起进步。 学习C++编译环境:Linux 第六十三课 C语言异常处理 1.异常处理 异常的概念 程序在运行过程中可能产生异常 异常(Exception)与Bug的区别 异常是程序运行时可预料的执行分支 Bug是程序中的错误,是不被预期的运行方式 异常(Exception)与Bug的对比: 异常: 运行时产生除0的情况 需要打开的外部文件不...

YLC_慕类的博客 472

【Linux系统编程】进程环境 跳转函数/资源获取

跳转函数 资源获取

2401_86738532的博客 193

关于TCP或FTP异常断开的处理方法总结

  最近在项目中遇到一些小小的问题,犯过的错希望不要犯二次。我Linux环境下开启一个TCP服务和FTP客户端用来升级系统,正常情况下是没任何差错的,如果断网(拔网线)或者PC端升级软件(QT软件)崩溃(强行退出),系统就会出现问题,   流程有2个,一个是FTP下载过程,一个是Flash写入过程,都涉及进度值的上传,即无时无刻都在调用write函数,并且进度函数的返回值是不处理的,也...

weixin_30278311的博客 736

TLPI 第6章 读书笔记:Processes

**从内核的角度来看,进程包含用户空间的内存,其中有程序代码以及该代码使用的变量,还有一系列内核数据结构,用于维护有关进程状态的信息。**记录在内核数据结构中的信息包括与进程相关的各种标识编号(ID)、虚拟内存表、打开文件描述符表、与信号传递和处理相关的信息、进程资源使用情况及限制、当前工作目录,以及大量其他信息。

In-Memory Computing Technology 577

彻底理解setjmp/longjmp并DIY一个简单的协程

上海昔日的邻居来杭州,我们小聚。今天一起带着小小去了西溪湿地,体验并不是太好,门票太贵,进去需乘船,船票快顶得上门票了,简直就是要抢劫啊!不过,景点嘛,一般我是不去的。 缘由 下面的代码写于5月2日(也就是今天刚开始的时候)凌晨1点钟,假期首日逛玩了一天,晚上自己写个东西玩玩,主要是因为之前想用setjmp/longjmp通过修改jmp_buf结构体的某些寄存器字段而实现协程而没有成功,就自己做个...

TCP/IP 1万+

linux——setjmp()和longjmp()函数的使用

setjmp()和longjmp()函数 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~~~~~&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与刺激的abort()和exit()相比,goto语句看起来比较适合处理异常的情况。不过,goto是本地的,只能跳到所在函数内部的标号上,而不能将控制权转移到所在程序的任意地点。 &nbsp;&nbsp;&nbsp;&nbsp;

夜风的博客 2035

10.setjmp()与longjmp()

文章目录函数原型功能工作流程原理示例标准限制原因滥用后果优化编译器的问题起因示例 函数原型 #include <setjmp.c> int setjmp(jmp_buf); Retuns 0 on initial call, nonzero on return longjmp() void longjmp(jmp_buf env, val); 功能 能够让函数从嵌套的函数中跳出,返回到函数的调用者之一(当前调用者或者调用者的调用者,等等)。 工作流程 setjmp()为后续的longjmp

随手写下笔记和感悟 1279

setjmp和longjmp

此文是学习 C专家编程 中的笔记。 setjmp和longjmp是C语言所独有的,它们部分弥补了C语言有限的转移能力。 函数说明(来自wiki百科): int setjmp(jmp_buf env) 建立本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返

cscmaker的专栏 6206
上一篇: ActiveX in Visual studio 2008
下一篇: transparent CStatic
HelloDan
博客等级 码龄20年 187粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值