longjmp导致局部变量丢失

news2025/7/13 0:42:26

0 总结

  • longjmp与setjmp语句之间的变量赋值会丢失。
  • 变量须满足:
    1. 在调用setjmp函数中的局部变量(栈变量) ,全局变量不受影响
    2. 非volatile

解决方法:加volatile

1 问题复现

#include <setjmp.h>
#include <stdio.h>

int d = 4;
int e = 5;

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	sigjmp_buf local_sigjmp_buf;

	a = 10;
	if (sigsetjmp(local_sigjmp_buf, 0) == 0)
	{
		
		b = 20;
		d = 40;
		siglongjmp(local_sigjmp_buf, 1);
	}
	else
	{
		c = 30;
		e = 50;
	}
	printf("a = %d,b = %d,c = %d,d = %d, e = %d\n", a, b, c, d, e);

	return 0;
}

使用O1编译

执行结果:b=20赋值丢失

$ gcc -o main3 -Wall -g -ggdb -O1 -g3 -gdwarf-2 main3.c
$ ./main3
a = 10,b = 2,c = 30,d = 40, e = 50

使用O0编译

执行结果:符合预期

$ gcc -o main3 -Wall -g -ggdb -O0 -g3 -gdwarf-2 main3.c
$ ./main3
a = 10,b = 20,c = 30,d = 40, e = 50

2 原因与解法

编译器在O1优化下,把sigsetjmp与siglongjmp之间的局部变量赋值操作丢掉了。

对比:左侧gcc O0,右侧gcc O1
在这里插入图片描述

手册中已有说明,满足三个条件的变量赋值无效:

  • 变量属于setjmp所在函数的局部变量:必须是栈上的变量。
  • 变量在setjmp和longjmp之间有修改。
  • 变量没有volatile。
LONGJMP(3)                                                        Linux Programmer's Manual                                                       LONGJMP(3)

NAME
       longjmp, siglongjmp - nonlocal jump to a saved stack context

SYNOPSIS
       #include <setjmp.h>

       void longjmp(jmp_buf env, int val);

       void siglongjmp(sigjmp_buf env, int val);

NOTES
       The values of automatic variables are unspecified after a call to longjmp() if they meet all the following criteria:
       ·  they are local to the function that made the corresponding setjmp(3) call;
       ·  their values are changed between the calls to setjmp(3) and longjmp(); and
       ·  they are not declared as volatile.

解法很简单:加volatile

这类一旦发生很难排查,事后排查难度远大于代码review发现。

3 对PG的影响

Postgresql中的存在大量PG_TRY/PG_CATCH宏的使用:

例如
在这里插入图片描述

这类宏是对sigsetjmp、siglongjmp函数的一层封装:(这里给一段PG10的定义,比较简单)

// 全局变量
sigjmp_buf *PG_exception_stack = NULL;

// 宏定义
#define PG_TRY()  \
	do { \
		sigjmp_buf *save_exception_stack = PG_exception_stack; \
		ErrorContextCallback *save_context_stack = error_context_stack; \
		sigjmp_buf local_sigjmp_buf; \
		if (sigsetjmp(local_sigjmp_buf, 0) == 0) \
		{ \
			PG_exception_stack = &local_sigjmp_buf

#define PG_CATCH()	\
		} \
		else \
		{ \
			PG_exception_stack = save_exception_stack; \
			error_context_stack = save_context_stack

#define PG_END_TRY()  \
		} \
		PG_exception_stack = save_exception_stack; \
		error_context_stack = save_context_stack; \
	} while (0)

对于这几个宏,在使用时需要注意:

如果在PG_TRY里面修改了栈变量,一定要确认变量加了volatile,全局变量不受影响。
在这里插入图片描述

新版本的PG也在注释中做了提示。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/17887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

H5的基础

网页的学名称作HTML文件&#xff0c;是一种可以在www网上传输&#xff0c;并被浏览器认识和翻译成页面显示出来的文件。 HTML是&#xff1a;Hypertext Marked Language即超文本标记语言&#xff0c;是一种用来制作超文本文档的简单标记语言 超文本就是指页面内可以包含图片&…

六十分之九十——沉迷期的突破

目录一、目标二、计划三、完成情况四、提升改进(最少3点)五、意外之喜(最少2点)六、总结一、目标 明确可落地&#xff0c;对于自身执行完成需要一定的努力才可以完成的 1.8本技术管理书籍阅读(使用番茄、快速阅读、最后输出思维导图)2.得到"逻辑思维"、吴军硅谷来信…

WebRTC GCC 拥塞控制算法(REMB-GCC)

目录 一. 前言 二. REMB-GCC算法原理 1. 接收端基于延时梯度的带宽预估 &#xff08;1&#xff09;Arrival-time filter &#xff08;2&#xff09;Overuse Detector &#xff08;3&#xff09;Adaptive threshold &#xff08;4&#xff09;Remote Rate Controller &a…

【SQL】之索引

【SQL】之索引简单的索引设计方式innodb中的索引设计方式迭代一次迭代两次迭代三次btree聚簇索引二级索引&#xff08;非聚簇&#xff09;联合索引&#xff08;非聚簇&#xff09;InnoDB的B树索引的注意事项myISAM中索引设计方案索引是帮助mysql高效获取数据的数据结构简单的索…

查询

一、顺序查询 普通查找方式&#xff1a; int SeqSearch(int a[],int n,int k) {int i 0;while (i < n && a[i] ! k)i;if (i > n)return 0;elsereturn i 1; } 优化版查找方式&#xff1a; int OPSeqSearch(int a[], int n, int k) {int i 0;a[n] k;while …

全志A33使用主线U-Boot方法

最近在研究A33主线相关的资源&#xff0c;目前主线uboot和内核都对A33有极好的支持了&#xff0c;所以现在把我在使用过程中遇到的问题和使用方法做个记录&#xff0c;首先是下载主线uboot源码&#xff0c;网址为https://ftp.denx.de/pub/u-boot/&#xff0c;我下载的版本为202…

点云 ICP学习-IterativeClosestPoint

目录 一、pcl中 点云配准算法 二、关于svd原理求解部分 三、pcl IterativeClosestPoint 完成demo 一、pcl中 点云配准算法 PCL 库中 ICP 的接口及其变种&#xff1a; 点到点&#xff1a;pcl::IterativeClosestPoint< PointSource, PointTarget, Scalar >点到面&…

RocketMQ——Mac电脑OS系统docker安装Dashboard

文章目录引言安装下载dashboard镜像docker pull镜像查看镜像运行容器启动容器查看容器日志问题解决方案解决方案说明登录dashboard界面关注微信公众号&#xff1a;CodingTechWork&#xff0c;一起学习进步。引言 前面的文章已经介绍过如何在OS系统上安装并启动使用RocketMQ&…

Canal 安装与入门

MySQL Binlog 简介 https://blog.csdn.net/weixin_44371237/article/details/127904514 MySQL 主从复制过程 1&#xff09;Master 主库将改变记录&#xff0c;写到二进制日志(Binary Log)中&#xff1b; 2&#xff09;Slave 从库向 MySQL Master 发送 dump 协议&#xff0c…

基于QT的考试管理系统设计与实现

目录 一、项目概要 4 1.1项目名称 4 1.2项目目标 4 1.3软件概要 4 1.4功能描述 5 1.5开发环境 5 1.6关键技术 6 1.7开发体制 6 1.8开发阶段 6 二、软件详细需求 7 2.1学生登陆主界面 7 2.2管理员登陆主界面 8 2.3 学生考试系统实现 9 2.4学生练习系统实现 10 2.5试题管理系统实…

mongoDB mapreduce使用总结

大家都知道&#xff0c;mongodb是一个非关系型数据库&#xff0c;也就是说&#xff0c;mongodb数据库中的每张表是独立存在的&#xff0c;表与表之间没有任何依赖关系。在mongodb中&#xff0c;除了各种CRUD语句之外&#xff0c;还给我们提供了聚合和mapreduce统计的功能&#…

JVM 彻底搞懂JVM内存区域及直接内存

面试题&#xff1a;直接内存会导致OOM么&#xff1f; 程序计数器 代表当前线程所执行的字节码所在的行号&#xff0c;配合字节码解释器获取下一条需要执行的字节码指令。 代码中的分支、循环、跳转、异常处理、线程恢复都要依靠它来实现。 程序计数器是线程私有的&#xff0…

进程控制的一些具体操作

目录进程控制进程终止进程退出的方式进程等待进程等待的方法wait使用方法waitpid使用方法进程程序替换替换函数execl函数execv函数execlp函数execvp函数execle函数execve函数---->只有这一个是系统调用&#xff0c;其他都是库函数execvpe函数补充几个知识: %s/被替换的文件…

代码随想录——冗余连接II(并查集)

题目 在本问题中&#xff0c;有根树指满足以下条件的 有向 图。该树只有一个根节点&#xff0c;所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点&#xff0c;而根节点没有父节点。 输入一个有向图&#xff0c;该图由一个有着 n 个节点&am…

vb.net自定义白板

希沃白板在学校里基本上是一直使用的&#xff0c;但是在非希沃电脑里面是没有启动白板的 简答介绍思路和具体的功能 1、背景颜色和画笔颜色自由切换、画笔粗细1~20可以调节。 2、画笔样式&#xff1a;虚线、点线、短线 3、基本图形&#xff1a;矩形&#xff0c;正方形&…

程序员级别分析,看看你是哪个级别

关于程序员的工资众说纷纭&#xff0c;有说开七八千的&#xff0c;也有人说每月上万的&#xff0c;但不管怎么说&#xff0c;程序员的工资是真的比一些文职、行政人员岗位挣得多&#xff0c;大家都是靠自己的能力赚钱&#xff0c;这没什么可比的&#xff0c;况且大家都是在学习…

JAVASE零基础到高级教程(1)------ 集成开发环境安装使用

一 什么是环境变量 环境变量是在操作系统中⼀个具有特定名字的对象&#xff0c;它包含了⼀个或者多个应⽤程序所将使⽤到的 信息。例如Windows和DOS操作系统中的path环境变量&#xff0c;当要求系统运⾏⼀个程序⽽没有告诉它程 序所在的完整路径时&#xff0c;系统除了在当前⽬…

前端框架 Electron 使用总结

目录 一、基础搭建 通过脚手架搭建 1、Electron官方案例搭建环境 2、查看调试 3、菜单的使用 4、图标配置 5、项目打包 web应用相信每位程序员都不陌生&#xff0c;PC端应用可能会底层开发的就不是太多了&#xff0c;下面的这套技术栈就是为前端程序员快速一键搭建windo…

Linux学习——网络编程基础及TCP服务器

目录 一、网络采用分层的思想&#xff1a; 二、各层典型的协议&#xff1a; 三、网络的封包和拆包&#xff1a; 四、网络编程的预备知识 4.1.SOCKET 4.2 IP地址 4.3 端口号 4.4 字节序 五、TCP编程API TCP协议分成了两个不同的协议&#xff1a;可靠传输&#xff1a;用来检测网络…

读书笔记-学习GNU Emacs-3终篇

学习本书目的&#xff1a; emacs的学习一直是陆陆续续看博客和上手实践&#xff0c;这次想通过阅读"学习GNU Emacs"这本书好好系统的再复习下emacs。 yps:读技术书应该是带着一定的目的去读的&#xff0c;最简单的目的可能就是为了学好某一项技术或者复习下某一项技…