]> granicus.if.org Git - clang/commitdiff
[MS ABI] Don't crash when zero-initializing a vbase which contains a vbase
authorDavid Majnemer <david.majnemer@gmail.com>
Thu, 12 May 2016 03:51:52 +0000 (03:51 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Thu, 12 May 2016 03:51:52 +0000 (03:51 +0000)
Bases can be zero-initialized: the storage is zero-initialized before
the base constructor is run.
The MS ABI has a quirk where base VBPtrs are not installed by the
base constructor but by the most derived class.  In particular, they are
installed before the base constructor is run.
The derived constructor must be careful to zero-initialize only the bits
of the class which haven't already been populated by virtual base
pointers.

While we correctly avoided this scenario, we didn't handle the case
where the base class has virtual bases which have virtual bases.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269271 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprCXX.cpp
test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp

index c6f46c3969b071b3b30bb703ce86f9f0379a003f..7e17c55ee60852a47cbe4db94a1aa05c400be9c8 100644 (file)
@@ -370,6 +370,9 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
   std::vector<CharUnits> VBPtrOffsets =
       CGF.CGM.getCXXABI().getVBPtrOffsets(Base);
   for (CharUnits VBPtrOffset : VBPtrOffsets) {
+    // Stop before we hit any virtual base pointers located in virtual bases.
+    if (VBPtrOffset >= NVSize)
+      break;
     std::pair<CharUnits, CharUnits> LastStore = Stores.pop_back_val();
     CharUnits LastStoreOffset = LastStore.first;
     CharUnits LastStoreSize = LastStore.second;
index 7d13a393c49c84e08fb21f933f7a66088b5c5bd1..480ae8cfbbec09a0b5a503d95d85afee136cee4e 100644 (file)
@@ -499,3 +499,25 @@ void callit(C *p) {
 // CHECK: %[[B_i8:.*]] = getelementptr i8, i8* %{{.*}}, i32 4
 // CHECK: call x86_thiscallcc void @"\01?g@C@pr27621@@UAEXXZ"(i8* %[[B_i8]])
 }
+
+namespace test6 {
+class A {};
+class B : virtual A {};
+class C : virtual B {
+  virtual void m_fn1();
+  float field;
+};
+class D : C {
+  D();
+};
+D::D() : C() {}
+// CHECK-LABEL: define x86_thiscallcc %"class.test6::D"* @"\01??0D@test6@@AAE@XZ"(
+// CHECK:   %[[THIS:.*]] = load %"class.test6::D"*, %"class.test6::D"**
+// CHECK:   br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+
+// CHECK: %[[SKIP_VBASES]]
+// CHECK:   %[[C:.*]] = bitcast %"class.test6::D"* %[[THIS]] to %"class.test6::C"*
+// CHECK:   %[[C_i8:.*]] = bitcast %"class.test6::C"* %[[C]] to i8*
+// CHECK:   %[[FIELD:.*]] = getelementptr inbounds i8, i8* %[[C_i8]], i32 8
+// CHECK:   call void @llvm.memset.p0i8.i32(i8* %[[FIELD]], i8 0, i32 4, i32 4, i1 false)
+}