abi::__dynamic_cast向上转型返回nullptr问题排查与解决求助
钩子C++异常抛出机制时
abi::__dynamic_cast向上转型返回nullptr的问题 场景说明
我需要通过钩子__cxxabiv1命名空间下的__cxa_throw函数拦截C++异常抛出,在抛出时若为自定义异常类型或其子类,就修改其中的成员值,钩子框架如下:
namespace __cxxabiv1 { extern "C" void __cxa_throw(void* voidPointerToActualObject, std::type_info* stdTypeInfoOfActualObject, void (*destructor)(void *)) { // 若抛出的异常是自定义类型或其子类,向其中写入值 } }
我编写了包含简单继承层级的测试代码验证逻辑:
#include <stdexcept> class Upper : public std::exception { public: int pokeMe = 111111; }; class Lower : public Upper {}; int main() { throw Lower(); } #include <cxxabi.h> namespace __cxxabiv1 { extern "C" void __cxa_throw(void* voidPointerToActualObject, std::type_info* stdTypeInfoOfActualObject, void (*destructor)(void *)) { // 这段代码可以正常工作: Lower* staticallyTypedPointerToActualObject = reinterpret_cast<Lower*>(voidPointerToActualObject); auto thisWorks = dynamic_cast<Upper*>(staticallyTypedPointerToActualObject); thisWorks->pokeMe = 222222; // 但当未知实际静态类型时,仅通过void*和type_info调用abi::__dynamic_cast向上转型返回nullptr: auto abiTypeInfoOfActualObject = dynamic_cast<const abi::__class_type_info*>(stdTypeInfoOfActualObject); auto abiTypeInfoOfUpper = dynamic_cast<const abi::__class_type_info*>(&typeid(Upper)); Upper* thisDoesNotWork = reinterpret_cast<Upper*>(abi::__dynamic_cast(voidPointerToActualObject, abiTypeInfoOfActualObject, abiTypeInfoOfUpper, -1)); thisDoesNotWork->pokeMe = 333333; // 省略:调用原始__cxa_throw函数 // 以下代码用于抑制警告: (void)destructor; // 未使用参数 while (1) { } // 从不返回的函数 } }
核心问题
我认为abi::__dynamic_cast应该支持向上转型,但实际调用时却返回nullptr。请问这是什么原因?该如何解决?
另外测试发现,这个函数的向下转型可以正常工作:
auto abiTypeInfoOfActualObject = dynamic_cast<const abi::__class_type_info*>(&typeid(Upper)); // 测试用 auto abiTypeInfoOfUpper = dynamic_cast<const abi::__class_type_info*>(&typeid(Lower)); // 转为Lower而非Upper Lower* thisDoesNotWork = reinterpret_cast<Lower*>(abi::__dynamic_cast(voidPointerToActualObject, abiTypeInfoOfActualObject, abiTypeInfoOfUpper, -1));
原因分析与解决方案
原因
abi::__dynamic_cast的第四个参数src2dst_offset代表源对象相对于传入指针的偏移量:
- 当传入
-1时,函数会认为要进行交叉转型或需要自动计算偏移的复杂转型; - 但单继承场景下的向上转型,源对象(派生类)指针与基类指针偏移量为0,传入
-1会导致函数无法正确识别转型路径,最终返回nullptr。
解决方案
将abi::__dynamic_cast的第四个参数从-1改为0,适配单继承向上转型的偏移量要求:
auto abiTypeInfoOfActualObject = dynamic_cast<const abi::__class_type_info*>(stdTypeInfoOfActualObject); auto abiTypeInfoOfUpper = dynamic_cast<const abi::__class_type_info*>(&typeid(Upper)); // 将第四个参数改为0 Upper* nowWorks = reinterpret_cast<Upper*>(abi::__dynamic_cast(voidPointerToActualObject, abiTypeInfoOfActualObject, abiTypeInfoOfUpper, 0)); if (nowWorks != nullptr) { nowWorks->pokeMe = 333333; }
补充说明
- 向下转型时传入
-1可以让函数自动计算基类到派生类的指针偏移量,这也是你测试中向下转型能正常工作的原因; - 多继承或虚拟继承场景下,需根据实际继承结构调整偏移量,或通过
-1让函数自动计算; - 转型后务必检查指针是否为nullptr,避免空指针访问。
内容的提问来源于stack exchange,提问作者Niko O
相关产品推荐
相关产品推荐

