NoQ created this revision.
NoQ added reviewers: dcoughlin, xazax.hun, a_sidorin, rnkovacs, 
mikhail.ramalho, Szelethus, baloghadamsoftware.
Herald added subscribers: cfe-commits, Charusso, jdoerfert, dkrupp, donat.nagy, 
a.sidorin, szepet.
Herald added a project: clang.

I'll add more tests soon, to see if it is actually initialized *correctly* now, 
but for now here's the code that fixes the crash in 
https://bugs.llvm.org/show_bug.cgi?id=40022 .

It turns out that C++17 aggregate initialization with base classes wasn't 
really ever implemented for the case when it *doesn't* involve calling any 
sub-object constructors. That it, when the aggregate is initialized with a 
simple initializer list and the resulting value is a `nonloc::CompoundVal`, we 
simply didn't know that we need to perform the store bind for the base classes 
as well. Now it should work.

The original bug report causes us to crash when there's a flexible array at the 
end of the structure (which is a non-standard thing), which made me 
underestimate the problem a bit :)

The case where we *do* have constructors in base classes is, of course, still 
unimplemented; it was last touched in D40841 <https://reviews.llvm.org/D40841>.


Repository:
  rC Clang

https://reviews.llvm.org/D59054

Files:
  clang/lib/StaticAnalyzer/Core/RegionStore.cpp
  clang/test/Analysis/array-struct-region.cpp


Index: clang/test/Analysis/array-struct-region.cpp
===================================================================
--- clang/test/Analysis/array-struct-region.cpp
+++ clang/test/Analysis/array-struct-region.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
 // RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ 
-analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ 
-std=c++17 -analyzer-config c++-inlining=constructors %s
 // RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
 // RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ 
-analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ 
-std=c++17 -analyzer-config c++-inlining=constructors %s
 
 void clang_analyzer_eval(int);
 
@@ -196,4 +198,21 @@
   }
 }
 
+namespace flex_array_inheritance_cxx17 {
+struct A {
+  int flexible_array[];
+};
+
+struct B {
+  long cookie;
+};
+
+struct C : B {
+  A a;
+};
+
+void k() {
+  C c{};
+}
+} // namespace flex_array_inheritance_cxx17
 #endif
Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2337,9 +2337,37 @@
   const nonloc::CompoundVal& CV = V.castAs<nonloc::CompoundVal>();
   nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
 
-  RecordDecl::field_iterator FI, FE;
   RegionBindingsRef NewB(B);
 
+  // In C++17 aggregates may have base classes, handle those as well.
+  // They appear before fields in the initializer list / compound value.
+  if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+    assert(CRD->isAggregate());
+
+    // Virtual bases still aren't allowed. Multiple bases are fine though.
+    for (auto B : CRD->bases()) {
+      assert(B.isVirtual() == false);
+
+      if (VI == VE)
+        break;
+
+      QualType BTy = B.getType();
+      assert(BTy->isStructureOrClassType());
+
+      const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl();
+      assert(BRD);
+
+      const CXXBaseObjectRegion *BR =
+          MRMgr.getCXXBaseObjectRegion(BRD, R, /*IsVirtual=*/false);
+
+      NewB = bindStruct(NewB, BR, *VI);
+
+      ++VI;
+    }
+  }
+
+  RecordDecl::field_iterator FI, FE;
+
   for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
 
     if (VI == VE)


Index: clang/test/Analysis/array-struct-region.cpp
===================================================================
--- clang/test/Analysis/array-struct-region.cpp
+++ clang/test/Analysis/array-struct-region.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -std=c++17 -analyzer-config c++-inlining=constructors %s
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -std=c++17 -analyzer-config c++-inlining=constructors %s
 
 void clang_analyzer_eval(int);
 
@@ -196,4 +198,21 @@
   }
 }
 
+namespace flex_array_inheritance_cxx17 {
+struct A {
+  int flexible_array[];
+};
+
+struct B {
+  long cookie;
+};
+
+struct C : B {
+  A a;
+};
+
+void k() {
+  C c{};
+}
+} // namespace flex_array_inheritance_cxx17
 #endif
Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2337,9 +2337,37 @@
   const nonloc::CompoundVal& CV = V.castAs<nonloc::CompoundVal>();
   nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
 
-  RecordDecl::field_iterator FI, FE;
   RegionBindingsRef NewB(B);
 
+  // In C++17 aggregates may have base classes, handle those as well.
+  // They appear before fields in the initializer list / compound value.
+  if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+    assert(CRD->isAggregate());
+
+    // Virtual bases still aren't allowed. Multiple bases are fine though.
+    for (auto B : CRD->bases()) {
+      assert(B.isVirtual() == false);
+
+      if (VI == VE)
+        break;
+
+      QualType BTy = B.getType();
+      assert(BTy->isStructureOrClassType());
+
+      const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl();
+      assert(BRD);
+
+      const CXXBaseObjectRegion *BR =
+          MRMgr.getCXXBaseObjectRegion(BRD, R, /*IsVirtual=*/false);
+
+      NewB = bindStruct(NewB, BR, *VI);
+
+      ++VI;
+    }
+  }
+
+  RecordDecl::field_iterator FI, FE;
+
   for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
 
     if (VI == VE)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to