[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
This commit is contained in:
Artem Dergachev 2018-08-29 22:05:35 +00:00
parent 8c95b48ba2
commit ed19831f63
3 changed files with 49 additions and 13 deletions

View File

@ -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

View File

@ -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);

View File

@ -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