您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C+异常原理:以一个小程序为例

时间:2023-07-11 15:14:44  来源: 阿里技术  作者:

阿里妹导读

作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。

最近我们在调查某个 bug 涉及到 C++ 异常。平时较少用 C++ 异常,借此机会把 C++ 异常机制梳理清楚。互联网上现有的资料不多,大多过于深奥。因此写下这篇文档备忘。

C++ 异常的实现机制有 SJLJ、Dwarf CFI、EHABI。具体选择哪种实现和操作系统及体系结构相关。它是 C++ ABI 的一部分。这里我们仅关注 Dwarf CFI,它是 linux 在 x86_64 和 arm64 上的默认实现。

完整的 C++ 异常机制需要编译器生成的代码、C++ 运行时(libstdc++ 或 libc++)、unwind 库分工协作完成。本文为了描述浅显易懂,并不区分它们三者。

测试程序

我们从下面的小程序出发,分析 C++ 异常的实现原理。这个程序演示了几个关键点:

1.f() 分配异常对象并抛出来;

2.向上回溯栈帧,沿途析构 g() 栈上的对象;

3.mAIn() 匹配到 catch 语句,处理异常。

抛出异常

为了方便描述,我们下面以 C 语法描述编译器为异常生成的代码。(小技巧:在 CompilerExplorer 网站能看到各种编译器生成的汇编代码。)

让我们先看抛异常的 f() 函数。它抛出了类型为 E 的异常,除此以外没有其它功能。

这些 __cxa 开头的函数是由 C++ 运行时库提供的。

__cxa_allocate_exception() 从堆上分配异常对象和其它内部数据结构。

__cxa_throw() 会向上回溯栈帧,依次回溯到 g() 和 main()。

传播异常

我们再来看 g()。g() 没有 catch 语句,异常会继续向上传播。但是在此之前还有一个栈上对象 a,因此回溯栈桢时需要在此停留,以析构 a 对象。

这里引出一个概念:着陆场(landing pad)。下面代码中第 9~10 行是 f() 正常返回的执行路径。若 f() 抛异常,则会跳转到第 15 行。这里称为着陆场。这里第 15 行析构了a 对象,第 16 行继续向上回溯到 main()。

捕获异常

最后来看 main()。main() 中有 catch 语句,第二个 catch 语句匹捕获到 E 类型的异常。

其它细节

前面埋了个包袱:__cxa_throw() 是回溯栈帧和找到着陆场呢?已知 PC 指针位置,这些信息编译时确定的。编译时产生 .eh_frame 和 .gcc_except_table 段,运行时借助这两张表可以找到上层栈帧和着陆场的位置。详细的描述过于复杂,请参考本文末尾的链接。

找到着陆场后,在运行时依次根据捕获的异常类型来匹配 catch 语句,这里用到了 C++ RTTI 信息。若匹配不到合适的 catch 语句,则继续向上回溯栈帧传播异常。

参考资料:

1、Itanium C++ ABI: Exception Handling:https://itanium-cxx-abi.Github.io/cxx-abi/abi-eh.html

2、Exception Handling ABI for the Arm Architecture:https://github.com/ARM-software/abi-aa/blob/844a79fd4c77252a11342709e3b27b2c9f590cf1/ehabi32/ehabi32.rst

3、libunwind LLVM Unwinder:https://github.com/llvm/llvm-project/blob/main/libunwind/docs/index.rst

4、Linux 栈回溯(x86_64):https://zhuanlan.zhihu.com/p/302726082

5、.eh_frame:https://www.airs.com/blog/archives/460

6、.gcc_except_table:https://www.airs.com/blog/archives/464



Tags:C+   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除。
▌相关推荐
阿里妹导读作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。最近我们在调查某个 bug 涉及到 C++ 异常。平时较少用 C++ 异常,借此机...【详细内容】
2023-07-11  Tags: C+  点击:(0)  评论:(0)  加入收藏
【CSDN 编者按】数百种编程语言层出不穷,关于谁优谁劣的争议也未曾断过,但为何总有这种争论的出现,本文作者直击要害地解析道:「答案很简单,因为我们懒。当大家学习了一种编程语...【详细内容】
2022-11-17  Tags: C+  点击:(186)  评论:(0)  加入收藏
▌简易百科推荐
阿里妹导读作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。最近我们在调查某个 bug 涉及到 C++ 异常。平时较少用 C++ 异常,借此机...【详细内容】
2023-07-11     阿里技术  Tags:C+   点击:(0)  评论:(0)  加入收藏
整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)一月一度的 TIOBE 榜单又发布了,快来看看 7 月的编程语言排行榜有什么最新变化吧!C++ 正在向 C 发起“进攻”!自从去年 12 月 C++ 在 TIOBE...【详细内容】
2023-07-10    CSDN  Tags:C++   点击:(0)  评论:(0)  加入收藏
人脸识别库ViewFaceCore 是一个使用 C# 开发的超简单的离线人脸识别库。( 基于 SeetaFace6 ),多平台支持, 开源、免费、跨平台 (win/linux)。支持的.NET 版本, .NET Framework...【详细内容】
2023-07-03  攻城大狮哥    Tags:C#   点击:(8)  评论:(0)  加入收藏
大家好,我是华山自控编程朱老师前几天一个学员在学习C#与TryCatch用法时,也不知道TryCatch用法装可以用来做什么 。下面我们就详细讲讲C# 和封TryCatch用法相关知识。C# 是一...【详细内容】
2023-07-02  华山自控编程    Tags:C#   点击:(8)  评论:(0)  加入收藏
前面写了一篇用C语言实现一个万能单向链表,后来我想了下。在工作开发中,貌似用到队列这种机制的情况更常见。所以,本次用C语言写一个万能的队列。简单介绍下,队列是一种严格的线...【详细内容】
2023-06-27  记录我的编程生活  今日头条  Tags:C语言   点击:(22)  评论:(0)  加入收藏
作者 | Joydip Kanjilal编译 | 王瑞平意大利面是一种很好吃的食物,但是,如果用它来形容代码意味着这种程序很糟糕。“意大利面条式代码”是一个术语,用于描述组织不良、纠缠不...【详细内容】
2023-06-21    51CTO  Tags:C#   点击:(29)  评论:(0)  加入收藏
在使用任何语言编写程序时,您需要使用各种变量来存储各种信息。变量只是保留内存位置来存储值。 这意味着当你创建一个变量时,你在内存中保留一些空间。您可能喜欢存储各种数...【详细内容】
2023-06-14  原在路上路途阳光    Tags:c++   点击:(46)  评论:(0)  加入收藏
判断字符串为空有好几种方法:方法一: 代码如下:static void Main(string[] args) { string str = ""; if (str == "") { Console.WriteLine("a is empty"); ; } Console.ReadKe...【详细内容】
2023-06-13  opendotnet    Tags:C#   点击:(37)  评论:(0)  加入收藏
Swifter.Json 是一个高性能、功能丰富的 C# JSON 序列化和反序列化工具。它使用了许多优秀的技术来提高序列化和反序列化的速度,并且具有许多有用的功能,例如支持多种日期时间...【详细内容】
2023-06-12  步伐科技  今日头条  Tags:C#   点击:(44)  评论:(0)  加入收藏
微软于今天在 Marketplace 上架了一款适用于 Visual Studio Code 的官方 C# 开发套件 —— C# Dev Kit,通过更好地管理、测试,以及提供全新的 AI 功能,为 Linux、mac...【详细内容】
2023-06-09  OSC开源社区    Tags:C#   点击:(32)  评论:(0)  加入收藏
站内最新
站内热门
站内头条