r326247 - [analyzer] Fix trivial copy for empty objects.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 27 13:10:08 PST 2018


Author: dergachev
Date: Tue Feb 27 13:10:08 2018
New Revision: 326247

URL: http://llvm.org/viewvc/llvm-project?rev=326247&view=rev
Log:
[analyzer] Fix trivial copy for empty objects.

The SVal for any empty C++ object is an UnknownVal. Because RegionStore does
not have binding extents, binding an empty object to an UnknownVal may
potentially overwrite existing bindings at the same offset.

Therefore, when performing a trivial copy of an empty object, don't try to
take the value of the object and bind it to the copy. Doing nothing is accurate
enough, and it doesn't screw any existing bindings.

Differential Revision: https://reviews.llvm.org/D43714

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/test/Analysis/ctor.mm

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=326247&r1=326246&r2=326247&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Tue Feb 27 13:10:08 2018
@@ -42,19 +42,30 @@ void ExprEngine::performTrivialCopy(Node
                                     const CallEvent &Call) {
   SVal ThisVal;
   bool AlwaysReturnsLValue;
+  const CXXRecordDecl *ThisRD = nullptr;
   if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
     assert(Ctor->getDecl()->isTrivial());
     assert(Ctor->getDecl()->isCopyOrMoveConstructor());
     ThisVal = Ctor->getCXXThisVal();
+    ThisRD = Ctor->getDecl()->getParent();
     AlwaysReturnsLValue = false;
   } else {
     assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
     assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
            OO_Equal);
     ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
+    ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
     AlwaysReturnsLValue = true;
   }
 
+  assert(ThisRD);
+  if (ThisRD->isEmpty()) {
+    // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal
+    // and bind it and RegionStore would think that the actual value
+    // in this region at this offset is unknown.
+    return;
+  }
+
   const LocationContext *LCtx = Pred->getLocationContext();
 
   ExplodedNodeSet Dst;

Modified: cfe/trunk/test/Analysis/ctor.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/ctor.mm?rev=326247&r1=326246&r2=326247&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/ctor.mm (original)
+++ cfe/trunk/test/Analysis/ctor.mm Tue Feb 27 13:10:08 2018
@@ -729,3 +729,23 @@ namespace NoCrashOnEmptyBaseOptimization
     S s;
   }
 }
+
+namespace EmptyBaseAssign {
+struct B1 {};
+struct B2 { int x; };
+struct D: public B1, public B2 {
+const D &operator=(const D &d) {
+  *((B2 *)this) = d;
+  *((B1 *)this) = d;
+  return *this;
+}
+};
+
+void test() {
+  D d1;
+  d1.x = 1;
+  D d2;
+  d2 = d1;
+  clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}}
+}
+}




More information about the cfe-commits mailing list