Linux下boost::archive::binary_iarchive构造崩溃无异常抛出问题
问题成因分析
- 首先是Boost反序列化组件的输入校验缺失:Boost 1.58版本的
binary_iarchive在反序列化std::string类型时,会先从输入流读取长度字段,直接按照该长度申请内存存储字符串内容,不会对长度字段的合法性做前置校验。当文件被篡改后,长度字段会变成异常大的数值,触发超大内存申请操作。 - 其次是示例代码存在两处错误,放大了异常风险:
DeSerialization函数的第一个入参定义为const MetaData &object,反序列化需要修改目标对象内容,传const引用属于未定义行为,部分编译器会生成异常的内存写入逻辑。- main函数中调用
Serialization时传入的是ofstream类型名而非已实例化的OutputStream对象,属于笔误,实际运行会编译失败。
Linux下异常无法捕获的原因
- 从崩溃栈可以明确看到,内存申请流程被VMware的
libvmacore.so库hook,当超大内存申请失败时,该库没有遵循C标准抛出std::bad_alloc异常,而是直接调用PanicExit触发abort()终止进程。abort()本质是向进程发送SIGABRT信号,不属于C异常体系的范畴,所以catch(...)无法捕获。 - Windows平台的差异原因:Windows下的STL默认开启了new的异常抛出机制,且没有第三方库hook内存申请流程,内存申请失败会抛出标准异常,所以可以被
catch(...)捕获。
修复建议
- 先修复代码错误:将
DeSerialization的第一个入参改为非const引用,修正序列化调用的入参错误。
- 先修复代码错误:将
- 反序列化前新增自定义校验逻辑:序列化时先写入固定Magic头和数据块总长度,反序列化时先校验Magic头和长度是否在合理范围内,再传给Boost做反序列化。
- 如果无法移除
libvmacore.so的hook,可以通过注册SIGABRT信号处理函数做进程退出前的兜底处理。
- 如果无法移除
内容的提问来源于stack exchange,提问作者Jagadeesh Boggarapu
相关产品推荐
相关产品推荐

