如何让GCC或Clang编译包含不可达代码在内的全部代码
问题说明
测试代码如下:
void f() { int* ptr = 0; try { *ptr = 9; } catch (...) { printf("caught"); } }
默认编译参数下,GCC和Clang会将空指针解引用判定为C++标准定义的未定义行为(UB),基于“触发未定义行为的代码路径永远不会到达”的优化假设,直接剔除对应的catch(...)块生成逻辑,无法保留完整的异常处理路径。
编译参数配置
两款编译器都可以通过指定对应参数,关闭相关优化,强制保留所有代码和异常处理逻辑:
GCC 配置
需要添加的编译参数:
-O0:使用最低优化等级,最大程度保留源码对应的代码结构,避免其他优化逻辑干扰异常路径生成-fexceptions:强制开启C++异常支持,生成完整的栈展开、异常处理表元数据-fno-delete-null-pointer-checks:禁止编译器基于“空指针永远不会被合法解引用”的假设做代码路径裁剪-fno-prune-eh:禁止编译器静态分析异常触发概率,直接删除判定为“不会被触发”的catch块-fno-unreachable-code:关闭不可达代码消除逻辑,所有源码中出现的代码都会被生成对应汇编
示例编译命令:
g++ test.cpp -O0 -fexceptions -fno-delete-null-pointer-checks -fno-prune-eh -fno-unreachable-code -o test
Clang 配置
Clang大部分参数和GCC兼容,需要添加的参数如下:
-O0:关闭优化,保留原始代码结构-fexceptions:开启C++异常支持-fno-delete-null-pointer-checks:关闭空指针解引用相关的优化假设-fno-prune-eh:禁止裁剪异常处理块,保留所有catch逻辑-fno-omit-frame-pointer:保留栈帧指针,方便异常抛出时的栈展开操作
示例编译命令:
clang++ test.cpp -O0 -fexceptions -fno-delete-null-pointer-checks -fno-prune-eh -fno-omit-frame-pointer -o test
额外说明
- 以上编译参数仅负责让编译器保留catch块的代码和对应异常处理元数据,用户态默认情况下空指针解引用触发的是SIGSEGV信号,不是C++异常,不会直接进入catch块。
- 针对内核到用户态的C异常传递场景,需要在内核的缺页异常处理逻辑中,按照目标平台的C ABI规范构造异常对象,调用
_Unwind_RaiseException等底层unwind接口发起异常栈展开,才能正确走到用户态定义的catch逻辑。 - 测试阶段建议关闭位置无关代码、栈保护等额外安全机制,避免这些机制插入的额外代码干扰异常栈遍历逻辑。
内容的提问来源于stack exchange,提问作者Дмитрий Воронецкий
相关产品推荐
相关产品推荐

