C++ 静态强制转换无效指针时,地址消毒器报告错误

C++ 静态强制转换无效指针时,地址消毒器报告错误,c++,c++11,gcc,address-sanitizer,C++,C++11,Gcc,Address Sanitizer,当静态地将未分配内存中的派生*强制转换为基*时,gcc的ASAN报告: 对于测试,我使用了以下设置: struct Base2 { int dummy; }; struct Base { int dummy2; }; struct Derived : public Base2, public virtual Base { }; Derived* derived = (Derived*)0x1122334455667788; /* some pointer into non-allocated

当静态地将未分配内存中的
派生*
强制转换为
基*
时,gcc的ASAN报告:

对于测试,我使用了以下设置:

struct Base2 { int dummy; };
struct Base { int dummy2; };
struct Derived : public Base2, public virtual Base { };

Derived* derived = (Derived*)0x1122334455667788; /* some pointer into non-allocated memory */
Base* base = static_cast<Base*>(derived); /* ASAN fails here */
struct Base2{int dummy;};
结构基{int dummy2;};
派生结构:public Base2,public virtual Base{};
派生*派生=(派生*)0x112233445667788;/*一些指针指向未分配的内存*/
Base*Base=静态_转换(派生);/*阿桑在这里失败了*/
为什么ASAN在此报告无效的读取访问?指针偏移量以及由此产生的正确指针值不应该在编译时已知吗

那么为什么这种读访问是必要的呢

指针是否应该偏移,从而得到正确的结果指针 值是否在编译时已知

不,实际上继承的类的偏移量在编译时是未知的,所以编译器在运行时通过访问vtable来计算它

下面是一个简单的例子:

Base *foo(Derived *p) {
  return static_cast<Base*>(p);
}

ASan抱怨,因为您试图访问导致segfault的某个随机内存地址。

首先,
0x112233445667788
不是您想象的那样。。。它很可能被截断为
0x55667788
,因为它是从int转换而来的。其次,不需要
virtual
,因为您不需要多次继承
Base
。最后,您的错误是关于一个空指针访问,而您在snipit中没有这样做-所以我认为没有人能给您一个正确的答复meaningful@UKMonkey“这在你的狙击手中是不会做的”-他会做的,铸造到虚拟继承的类需要vtable访问。@yugr没有虚拟函数,就没有vtable;这将为空ptr访问提供。。。。因此,实际上,虚拟继承是问题的根源。有趣。(我尽量避免出现死亡钻石的情况;所以我对虚拟继承的影响的理解有点模糊)听起来你有一个很好的答案:)@UKMonkey我认为如果存在虚拟基类(即使没有虚拟函数),你仍然需要vtable,因为编译器直到运行时才知道它们的偏移量。关于GCC4.8生成的代码,请参见下面的答案。
Base *foo(Derived *p) {
  return static_cast<Base*>(p);
}
movq    (%rdi), %rax     # Get vptr
addq    -24(%rax), %rdi  # Load offset of Base from vtable
movq    %rdi, %rax       # Return result
ret