summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h12
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp30
-rw-r--r--clang/test/Analysis/temporaries.cpp20
3 files changed, 49 insertions, 13 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index e279bff86a6..deb6d18a885 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -734,10 +734,14 @@ private:
///
/// If \p Result is provided, the new region will be bound to this expression
/// instead of \p InitWithAdjustments.
- ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
- const LocationContext *LC,
- const Expr *InitWithAdjustments,
- const Expr *Result = nullptr);
+ ///
+ /// Returns the temporary region with adjustments into the optional
+ /// OutRegionWithAdjustments out-parameter if a new region was indeed needed,
+ /// otherwise sets it to nullptr.
+ ProgramStateRef createTemporaryRegionIfNeeded(
+ ProgramStateRef State, const LocationContext *LC,
+ const Expr *InitWithAdjustments, const Expr *Result = nullptr,
+ const SubRegion **OutRegionWithAdjustments = nullptr);
/// Returns a region representing the first element of a (possibly
/// multi-dimensional) array, for the purposes of element construction or
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9634157a70f..04190deb7a8 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -283,11 +283,10 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
-ProgramStateRef
-ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
- const LocationContext *LC,
- const Expr *InitWithAdjustments,
- const Expr *Result) {
+ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
+ ProgramStateRef State, const LocationContext *LC,
+ const Expr *InitWithAdjustments, const Expr *Result,
+ const SubRegion **OutRegionWithAdjustments) {
// FIXME: This function is a hack that works around the quirky AST
// we're often having with respect to C++ temporaries. If only we modelled
// the actual execution order of statements properly in the CFG,
@@ -297,8 +296,11 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
if (!Result) {
// If we don't have an explicit result expression, we're in "if needed"
// mode. Only create a region if the current value is a NonLoc.
- if (!InitValWithAdjustments.getAs<NonLoc>())
+ if (!InitValWithAdjustments.getAs<NonLoc>()) {
+ if (OutRegionWithAdjustments)
+ *OutRegionWithAdjustments = nullptr;
return State;
+ }
Result = InitWithAdjustments;
} else {
// We need to create a region no matter what. For sanity, make sure we don't
@@ -418,11 +420,17 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
// The result expression would now point to the correct sub-region of the
// newly created temporary region. Do this last in order to getSVal of Init
// correctly in case (Result == Init).
- State = State->BindExpr(Result, LC, Reg);
+ if (Result->isGLValue()) {
+ State = State->BindExpr(Result, LC, Reg);
+ } else {
+ State = State->BindExpr(Result, LC, InitValWithAdjustments);
+ }
// Notify checkers once for two bindLoc()s.
State = processRegionChange(State, TR, LC);
+ if (OutRegionWithAdjustments)
+ *OutRegionWithAdjustments = cast<SubRegion>(Reg.getAsRegion());
return State;
}
@@ -2532,8 +2540,12 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
}
// Handle regular struct fields / member variables.
- state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
- SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
+ const SubRegion *MR = nullptr;
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr,
+ /*Result=*/nullptr,
+ /*OutRegionWithAdjustments=*/&MR);
+ SVal baseExprVal =
+ MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx);
const auto *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
diff --git a/clang/test/Analysis/temporaries.cpp b/clang/test/Analysis/temporaries.cpp
index 0819eb73415..4a0a9f194cc 100644
--- a/clang/test/Analysis/temporaries.cpp
+++ b/clang/test/Analysis/temporaries.cpp
@@ -1152,3 +1152,23 @@ void run() {
// and the non-definition decl should be found by direct lookup.
void T::foo(C) {}
} // namespace argument_virtual_decl_lookup
+
+namespace union_indirect_field_crash {
+union U {
+ struct {
+ int x;
+ };
+};
+
+template <typename T> class C {
+public:
+ void foo() const {
+ (void)(true ? U().x : 0);
+ }
+};
+
+void test() {
+ C<int> c;
+ c.foo();
+}
+} // namespace union_indirect_field_crash
OpenPOWER on IntegriCloud