diff options
| author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-08-29 22:05:35 +0000 |
|---|---|---|
| committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-08-29 22:05:35 +0000 |
| commit | ed19831f63223b9540862ccc3c6d185014b5f6b7 (patch) | |
| tree | e119d088c963c92cd8e7271baee4557880c38b4a | |
| parent | 8c95b48ba273b28e22912191bfc25e8a2144377f (diff) | |
| download | bcm5719-llvm-ed19831f63223b9540862ccc3c6d185014b5f6b7.tar.gz bcm5719-llvm-ed19831f63223b9540862ccc3c6d185014b5f6b7.zip | |
[CFG] [analyzer] Disable argument construction contexts for variadic functions.
The analyzer doesn't make use of them anyway and they seem to have
pretty weird AST from time to time, so let's just skip them for now.
Fixes a crash reported as pr37769.
Differential Revision: https://reviews.llvm.org/D50855
llvm-svn: 340977
| -rw-r--r-- | clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 12 | ||||
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 30 | ||||
| -rw-r--r-- | clang/test/Analysis/temporaries.cpp | 20 |
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 |

