记一次va_list导致的段错误崩溃排查

news/2026/1/20 14:49:38/文章来源:https://www.cnblogs.com/3to4/p/19506673

记一次va_list导致的段错误崩溃排查

问题

为了适配GTest框架到鸿蒙,需要让GTest的日志输出使用 OH_LOG_Print 函数,因此写出了类似下面的代码:

#include <cstdarg>
#include <cstdio>const char *RenderMsg(const char *fmt, ...)
{thread_local char renderBuf[2048];va_list args;va_start(args, fmt);int rendered = vsnprintf(renderBuf, sizeof(renderBuf) - 1, fmt, args);va_end(args);renderBuf[rendered] = '\0'; // abandon all bytes exceed.return renderBuf;
}#define GTEST_PRINTF(fmt, ...) printf("%s\n", RenderMsg(fmt, ##__VA_ARGS__))
#define GTEST_VPRINTF GTEST_PRINTFstatic void GPrintf(const char *fmt, ...)
{va_list args;va_start(args, fmt);GTEST_PRINTF(fmt, args); // 展开后是:printf("%s\n", RenderMsg(fmt, args)),非预期。va_end(args);
}int main()
{int num_disabled = 2;GTEST_PRINTF("  YOU HAVE %d DISABLED %s\n\n",num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); // OK, 展开后是:printf("%s\n", RenderMsg("  YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"))GPrintf("  YOU HAVE %d DISABLED %s\n\n",num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); // 错误
}

上述代码在 Linux 上能运行,结果是,显然第二个输出是异常的:

  YOU HAVE 2 DISABLED TESTSYOU HAVE 489683816 DISABLED TESTS

在鸿蒙上会段错误,显示崩溃在 vsnprintf 中:

Reason:Signal:SIGSEGV(SEGV_MAPERR)@000000000000000000  probably caused by NULL pointer dereference
Fault thread info:
Tid:47314, Name:om.example.arks
#00 pc 00000000000a5290 /system/lib/ld-musl-aarch64.so.1(strnlen+16)(0afe599f71bfbe812637821352708631)
#01 pc 00000000001ac87c /system/lib/ld-musl-aarch64.so.1(printf_core+2180)(0afe599f71bfbe812637821352708631)
#02 pc 00000000001abe70 /system/lib/ld-musl-aarch64.so.1(vfprintf+188)(0afe599f71bfbe812637821352708631)
#03 pc 00000000001b6474 /system/lib/ld-musl-aarch64.so.1(vsnprintf+164)(0afe599f71bfbe812637821352708631)
#04 pc 00000000002e8964 /data/storage/el1/bundle/libs/arm64/libmytest.so(testing::internal::RenderMsg(char const*, ...)+204)(f01dc55fe98c38079fa11f285d170d860a89d2e5)

分析

由于崩溃在 vsnprintf ,标准库不大可能有BUG,而 RenderMsg 本身是经过单测验证的函数,也没有问题,那么问题大概出现在 va_list 上。

注意到宏展开过程:

GTEST_PRINTF(fmt, args); // 展开后是:printf("%s\n", RenderMsg(fmt, args)),非预期。

这里 args 已经是一个 va_list 了,那么传递给 RenderMsg 的就是单个实参 args ,而非预期的 num_disabled, num_disabled == 1 ? "TEST" : "TESTS" 两个实参。而 fmt 的值是 " YOU HAVE %d DISABLED %s\n\n" ,所以导致第一个格式化控制符 %d 读取的是 args 中的前4字节(自然是看不懂的垃圾值),而第二个格式化控制符 %s 读取的是 args 中接下来的8字节(自然是无效地址,所以段错误)。

此问题解决方案也很简单,原因就是对于使用了 va_listGTEST_VPRINTF ,不能简单地直接用 GTEST_PRINTF ,而是要准备一个专门的接收 va_list 的版本:

#include <cstdarg>
#include <cstdio>const char *RenderMsg(const char *fmt, ...)
{thread_local char renderBuf[2048];va_list args;va_start(args, fmt);int rendered = vsnprintf(renderBuf, sizeof(renderBuf) - 1, fmt, args);va_end(args);renderBuf[rendered] = '\0'; // abandon all bytes exceed.return renderBuf;
}const char *RenderMsg(const char *fmt, va_list args) // 专用版本
{thread_local char renderBuf[2048];int rendered = vsnprintf(renderBuf, sizeof(renderBuf) - 1, fmt, args);renderBuf[rendered] = '\0'; // abandon all bytes exceed.return renderBuf;
}#define GTEST_PRINTF(fmt, ...) printf("%s\n", RenderMsg(fmt, ##__VA_ARGS__))
#define GTEST_VPRINTF(fmt, args) printf("%s\n", RenderMsg(fmt, args))static void GPrintf(const char *fmt, ...)
{va_list args;va_start(args, fmt);// GTEST_PRINTF(fmt, args); // 展开后是:printf("%s\n", RenderMsg(fmt, args)),非预期。GTEST_VPRINTF(fmt, args); // 展开后是:printf("%s\n", RenderMsg(fmt, args)),符合预期。va_end(args);
}int main()
{int num_disabled = 2;GTEST_PRINTF("  YOU HAVE %d DISABLED %s\n\n",num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); // OK, 展开后是:printf("%s\n", RenderMsg("  YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"))GPrintf("  YOU HAVE %d DISABLED %s\n\n",num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); // 错误
}

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

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

相关文章

新疆新东方烹饪学校学费多少,详细地址为你揭晓 - 工业品牌热点

在西域美食文化蓬勃发展的今天,一所有实力的烹饪学校是青年学子掌握技艺、实现职业梦想的关键桥梁。面对新疆本地众多烹饪教育机构,如何找到教学扎实、就业有保障的选择?以下依据不同学习需求,为你推荐乌鲁木齐及周…

2026最新特殊月子餐/贵阳月子中心推荐!贵阳南明区/贵阳市中心/花果园专业母婴护理机构权威指南 - 品牌推荐2026

引言 随着现代母婴护理需求的精细化升级,月子中心已成为产后家庭的重要选择,其中特殊月子餐的科学配置与个性化服务尤为关键。据中国妇幼保健协会最新行业报告显示,国内具备专业膳食研发能力的月子中心不足40%,而能…

裁纸机厂家哪个好?一文为你揭秘! - 星辉数控

裁纸机厂家哪个好?一文为你揭秘! 在家具制造行业,裁纸机是不可或缺的关键设备。它的性能优劣直接影响产品质量与生产效率,可市场上裁纸机厂家众多,到底裁纸机厂家哪个好呢?别着急,看完这些干货,你就能找到方向…

【软考每日一练006】文件索引节点(i-node)解构:从物理底层到多级寻址计算

【软考每日一练006】文件索引节点&#xff08;i-node&#xff09;解构&#xff1a;从物理底层到多级寻址计算 在计算机世界中&#xff0c;数据持久化是一切应用的基础。而文件系统如何管理这些动辄数 GB 甚至 TB 的数据&#xff0c;并实现微秒级的定位&#xff1f;其核心秘密就…

测试工程师都在用的Linux命令清单(建议收藏)

作为一名工程师&#xff0c;熟练掌握Linux命令是基本功中的基本功。无论是日常工作中的系统维护&#xff0c;还是面试时的技术考核&#xff0c;Linux命令都是绕不开的核心技能。本文将从实战角度出发&#xff0c;系统梳理工程师必须掌握的Linux命令&#xff0c;并结合实际场景解…

【开题答辩全过程】以 茉莉园小区物业快速维修服务系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

(8-2)UENUM(..)

&#xff08;20&#xff09; &#xff08;21&#xff09; 谢谢

RPA直播间自动抢福袋神器 - 高级品牌推荐官

行业背景:2026年直播间风控与RPA抢福袋的技术博弈跨入2026年,全球及国内主流直播平台对“直播间福袋”与“互动奖励”的风控审计已达到生物特征级水平。传统的点击器或模拟器在具备AI深度学习能力的防作弊系统面前,…

(8-1)UENUM(..)

&#xff08;19&#xff09;&#xff08;20&#xff09; 谢谢

直播间自动抢福袋软件 - 高级品牌推荐官

行业背景:2026年直播间福袋风控的“全息审计”趋势步入2026年,全球及国内主流直播平台(如TikTok、抖音、快手等)对直播间互动奖励(福袋、红包)的风控审计已全面进入“全息身份识别”时代。传统的点击器或简单的模…

【软考每日一练007】位图计算与内存管理深度全解

【软考每日一练007】位图计算与内存管理深度全解 在操作系统的内存管理演进中&#xff0c;如何高效地记录和分配物理资源是系统性能的基石。本文将通过一道经典的笔试题&#xff0c;由浅入深地带你拆解页式存储管理、位图机制及其背后的跨模块设计逻辑。一、 经典例题 题目&…

浏览器RPA - 高级品牌推荐官

行业背景:2026年浏览器RPA从“模拟点击”向“AI Agent”的跨越步入2026年,全球数字营销与跨境电商行业已全面进入“超自动化”时代。传统的RPA(机器人流程自动化)软件如果仅停留在坐标模拟或简单的元素点击,在面对…

UE5 C++(37-3):

&#xff08;202&#xff09; &#xff08;203&#xff09; 谢谢

杭州市英语雅思培训辅导机构推荐,权威出国雅思课程中心学校口碑排行榜2026 - 老周说教育

依托英国文化教育协会(BC雅思)2026年1月最新发布的《2024-2025中国大陆雅思考生成绩大数据报告》核心指标,经浙江省教育考试院教学资质联合核验,结合杭州市西湖区、上城区、滨江区、余杭区、钱塘区、萧山区12000份…

推荐的工业AI大模型在制造业中的应用案例

工业AI大模型正逐渐成为现代制造业数字化转型的核心驱动力。与通用型AI模型不同&#xff0c;工业AI大模型深度融合行业知识、工艺流程与多模态数据&#xff0c;为制造企业提供从研发、生产到运营的全链路智能化解决方案。一、工业AI大模型的发展现状与特点工业AI大模型的发展并…

【改进差分优化算法L-SHADE-SPACMA】差分进化算法(DE)及其变体L-SHADE-SPACMA在CEC2005函数寻优的对比研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

Prometheus-4·监控mariadb数据库Grafana展示数据

一、监控mariadb数据库流程&#xff1a;在节点上安装数据库在节点安装mysql exporter配置监控端prometheus监控mysql导入展示模板查看mysql exporter数据二、环境准备&#xff1a;实验拓扑.pngPrometheus版本&#xff1a;prometheus-2.17.2.linux-386Grafana版本&#xff1a;gr…

【概率最小均方(PLMS)自适应滤波器】PLMS对高斯和非高斯噪声具有较强的鲁棒性附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

Deepoc具身模型:农业除草机器人的智能核心

在精准农业和智慧农业加速发展的时代&#xff0c;传统人工除草和化学除草方式正面临效率低、成本高、环境污染等挑战。Deepoc具身模型开发板的出现&#xff0c;为农业除草领域带来了从"人工识别"向"AI识别"、从"粗放作业"向"精准作业"…

代理ip哪家强 - 高级品牌推荐官

行业背景:2026年“强力”代理IP的定义变革跨入2026年,全球互联网生态的防御机制已进入“全路径AI指纹审计”时代。对于从事跨境电商、海外社媒矩阵管理、全球大数据抓取及精准营销的企业而言,评价代理IP“强不强”的…