https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70147
--- Comment #14 from Bernd Edlinger <bernd.edlinger at hotmail dot de> --- Hi Jakub, I played a bit with your proposed patch. consider this test case: cat test2.cc struct A { ~A() {} A () {} A (int x) : a (x) {} virtual void f () {} virtual int i () { return 0; } int a; }; struct E { E () { throw "something"; } E (int x) : e (x) {} virtual void f () {} virtual int g () { return 0; } int e; }; struct F { F () {} F (int x) : f (x) {} virtual int h () { return 0; } int f; }; struct B : virtual A, public E, public F { B () : E (), F () {} virtual void f () {} int b; }; struct D { D () {} D (int x) : d (x) {} virtual void f () {} int d; }; struct C : B, virtual A { C () {} } ; int main () { try { C c; } catch(...) { } } g++ -fsanitize=vptr test2.cc -fdump-tree-gimple test2.cc:6:32: runtime error: member call on address 0x7ffdf760fea0 which does not point to an object of type 'A' 0x7ffdf760fea0: note: object has invalid vptr 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c5 9e 26 d9 ^~~~~~~~~~~~~~~~~~~~~~~ invalid vptr this happens only due to the redundant initialization of vptr.A in B::B(), it is not undefined behavior: C::C() { if (1 != 0) goto <D.2984>; else goto <D.2985>; <D.2984>: D.2986 = &this->D.2844; A::A (D.2986); goto <D.2987>; <D.2985>: <D.2987>: try { D.2988 = &_ZTT1C + 8; D.2989 = &this->D.2842; B::B (D.2989, D.2988); ... } catch { if (1 != 0) goto <D.2998>; else goto <D.2999>; <D.2998>: D.3000 = &this->D.2844; D.3001 = D.3000->_vptr.A; -- B initialized vptr.A to null D.3002 = (long unsigned int) D.3001; UBSAN_VPTR (D.3000, D.3002, 18446725454765570473, &_ZTI1A, 4B); A::~A (D.3000); goto <D.3003>; <D.2999>: <D.3003>: } B::B() (struct B * const this, const void * * __vtt_parm) { MEM[(struct &)this] = {CLOBBER}; this->D.2711._vptr.E = 0B; D.3012 = MEM[(int (*__vtbl_ptr_type) () * *)__vtt_parm]; D.3013 = D.3012 + 18446744073709551592; D.3014 = MEM[(long int *)D.3013]; D.3015 = (sizetype) D.3014; D.3016 = this + D.3015; D.3016->_vptr.A = 0B; this->D.2712._vptr.F = 0B; { if (0 != 0) goto <D.3017>; else goto <D.3018>; <D.3017>: D.3019 = &this->D.2716; A::A (D.3019); goto <D.3020>; <D.3018>: <D.3020>: try { D.3021 = &this->D.2711; E::E (D.3021); -- this throws "something"