r327348 - [analyzer] Support temporaries conjured by conservatively evaluated functions.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 12 16:36:12 PDT 2018


Author: dergachev
Date: Mon Mar 12 16:36:12 2018
New Revision: 327348

URL: http://llvm.org/viewvc/llvm-project?rev=327348&view=rev
Log:
[analyzer] Support temporaries conjured by conservatively evaluated functions.

Properly perform destruction and lifetime extension of such temporaries.

C++ object-type return values of conservatively evaluated functions are now
represented as compound values of well-defined temporary object regions. The
function creates a region that represents the temporary object and will later
be used for destruction or materialization, invalidates it, and returns the
invalidated compound value of the object.

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

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/test/Analysis/explain-svals.cpp
    cfe/trunk/test/Analysis/temporaries.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=327348&r1=327347&r2=327348&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Mar 12 16:36:12 2018
@@ -581,23 +581,39 @@ ProgramStateRef ExprEngine::bindReturnVa
     return State->BindExpr(E, LCtx, ThisV);
   }
 
-  // Conjure a symbol if the return value is unknown.
+  SVal R;
   QualType ResultTy = Call.getResultType();
-  SValBuilder &SVB = getSValBuilder();
   unsigned Count = currBldrCtx->blockCount();
+  if (auto RTC = getCurrentCFGElement().getAs<CFGCXXRecordTypedCall>()) {
+    // Conjure a temporary if the function returns an object by value.
+    MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+    const CXXTempObjectRegion *TR = MRMgr.getCXXTempObjectRegion(E, LCtx);
+    State = addAllNecessaryTemporaryInfo(State, RTC->getConstructionContext(),
+                                         LCtx, TR);
 
-  // See if we need to conjure a heap pointer instead of
-  // a regular unknown pointer.
-  bool IsHeapPointer = false;
-  if (const auto *CNE = dyn_cast<CXXNewExpr>(E))
-    if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
-      // FIXME: Delegate this to evalCall in MallocChecker?
-      IsHeapPointer = true;
-    }
-
-  SVal R = IsHeapPointer
-               ? SVB.getConjuredHeapSymbolVal(E, LCtx, Count)
-               : SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
+    // Invalidate the region so that it didn't look uninitialized. Don't notify
+    // the checkers.
+    State = State->invalidateRegions(TR, E, Count, LCtx,
+                                     /* CausedByPointerEscape=*/false, nullptr,
+                                     &Call, nullptr);
+
+    R = State->getSVal(TR, E->getType());
+  } else {
+    // Conjure a symbol if the return value is unknown.
+
+    // See if we need to conjure a heap pointer instead of
+    // a regular unknown pointer.
+    bool IsHeapPointer = false;
+    if (const auto *CNE = dyn_cast<CXXNewExpr>(E))
+      if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
+        // FIXME: Delegate this to evalCall in MallocChecker?
+        IsHeapPointer = true;
+      }
+
+    R = IsHeapPointer ? svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count)
+                      : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy,
+                                                     Count);
+  }
   return State->BindExpr(E, LCtx, R);
 }
 

Modified: cfe/trunk/test/Analysis/explain-svals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/explain-svals.cpp?rev=327348&r1=327347&r2=327348&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/explain-svals.cpp (original)
+++ cfe/trunk/test/Analysis/explain-svals.cpp Mon Mar 12 16:36:12 2018
@@ -94,5 +94,5 @@ public:
 
 void test_6() {
   clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}}
-  clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'struct S' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+  clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
 }

Modified: cfe/trunk/test/Analysis/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=327348&r1=327347&r2=327348&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temporaries.cpp (original)
+++ cfe/trunk/test/Analysis/temporaries.cpp Mon Mar 12 16:36:12 2018
@@ -895,6 +895,45 @@ void test_ternary_temporary_with_copy(in
 }
 } // namespace test_match_constructors_and_destructors
 
+namespace destructors_for_return_values {
+
+class C {
+public:
+  ~C() {
+    1 / 0; // expected-warning{{Division by zero}}
+  }
+};
+
+C make();
+
+void testFloatingCall() {
+  make();
+  // Should have divided by zero in the destructor.
+  clang_analyzer_warnIfReached();
+#ifndef TEMPORARY_DTORS
+    // expected-warning at -2{{REACHABLE}}
+#endif
+}
+
+void testLifetimeExtendedCall() {
+  {
+    const C &c = make();
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+  // Should have divided by zero in the destructor.
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void testCopiedCall() {
+  C c = make();
+  // Should have divided by zero in the temporary destructor.
+  clang_analyzer_warnIfReached();
+#ifndef TEMPORARY_DTORS
+    // expected-warning at -2{{REACHABLE}}
+#endif
+}
+} // namespace destructors_for_return_values
+
 namespace dont_forget_destructor_around_logical_op {
 int glob;
 
@@ -922,8 +961,17 @@ void test(int coin) {
   // return value of get() was initialized. However, we didn't track
   // temporaries returned from functions, so we took the wrong branch.
   coin && is(get()); // no-crash
-  // FIXME: Should be true once we inline all destructors.
-  clang_analyzer_eval(glob); // expected-warning{{UNKNOWN}}
+  if (coin) {
+    clang_analyzer_eval(glob);
+#ifdef TEMPORARY_DTORS
+    // expected-warning at -2{{TRUE}}
+#else
+    // expected-warning at -4{{UNKNOWN}}
+#endif
+  } else {
+    // The destructor is not called on this branch.
+    clang_analyzer_eval(glob); // expected-warning{{UNKNOWN}}
+  }
 }
 } // namespace dont_forget_destructor_around_logical_op
 




More information about the cfe-commits mailing list