diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index ecff5c6623d9..712cd6361e11 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -332,9 +332,9 @@ public: void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex, - ExplodedNode *Pred, - ExplodedNodeSet &Dst); + void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); /// VisitGCCAsmStmt - Transfer function logic for inline asm. void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 31e21232408b..3be37e7ae301 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1150,7 +1150,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ArraySubscriptExprClass: Bldr.takeNodes(Pred); - VisitLvalArraySubscriptExpr(cast(S), Pred, Dst); + VisitArraySubscriptExpr(cast(S), Pred, Dst); Bldr.addNodes(Dst); break; @@ -2126,10 +2126,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } /// VisitArraySubscriptExpr - Transfer function for array accesses -void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, +void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNode *Pred, ExplodedNodeSet &Dst){ - const Expr *Base = A->getBase()->IgnoreParens(); const Expr *Idx = A->getIdx()->IgnoreParens(); @@ -2138,18 +2137,32 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNodeSet EvalSet; StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); - assert(A->isGLValue() || - (!AMgr.getLangOpts().CPlusPlus && - A->getType().isCForbiddenLValueType())); + + bool IsVectorType = A->getBase()->getType()->isVectorType(); + + // The "like" case is for situations where C standard prohibits the type to + // be an lvalue, e.g. taking the address of a subscript of an expression of + // type "void *". + bool IsGLValueLike = A->isGLValue() || + (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus); for (auto *Node : CheckerPreStmt) { const LocationContext *LCtx = Node->getLocationContext(); ProgramStateRef state = Node->getState(); - SVal V = state->getLValue(A->getType(), - state->getSVal(Idx, LCtx), - state->getSVal(Base, LCtx)); - Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + + if (IsGLValueLike) { + SVal V = state->getLValue(A->getType(), + state->getSVal(Idx, LCtx), + state->getSVal(Base, LCtx)); + Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, + ProgramPoint::PostLValueKind); + } else if (IsVectorType) { + // FIXME: non-glvalue vector reads are not modelled. + Bldr.generateNode(A, Node, state, nullptr); + } else { + llvm_unreachable("Array subscript should be an lValue when not \ +a vector and not a forbidden lvalue type"); + } } getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this); diff --git a/clang/test/Analysis/vector.c b/clang/test/Analysis/vector.m similarity index 58% rename from clang/test/Analysis/vector.c rename to clang/test/Analysis/vector.m index 32b568f6b002..e74c487d3a60 100644 --- a/clang/test/Analysis/vector.c +++ b/clang/test/Analysis/vector.m @@ -2,6 +2,7 @@ typedef int __attribute__((ext_vector_type(2))) V; +void clang_analyzer_warnIfReached(); void clang_analyzer_numTimesReached(); void clang_analyzer_eval(int); @@ -26,3 +27,35 @@ V dont_crash_and_dont_split_state(V x, V y) { clang_analyzer_numTimesReached(); // expected-warning{{2}} return z; } + +void test_read() { + V x; + x[0] = 0; + x[1] = 1; + + clang_analyzer_eval(x[0] == 0); // expected-warning{{TRUE}} +} + +V return_vector() { + V z; + z[0] = 0; + z[1] = 0; + return z; +} + +int test_vector_access() { + return return_vector()[0]; // no-crash no-warning +} + +@interface I +@property V v; +@end + +// Do not crash on subscript operations into ObjC properties. +int myfunc(I *i2) { + int out = i2.v[0]; // no-crash no-warning + + // Check that the analysis continues. + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} + return out; +}