summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp35
-rw-r--r--test/Analysis/vector.m (renamed from test/Analysis/vector.c)33
3 files changed, 60 insertions, 14 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index ecff5c6623..712cd6361e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/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/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 31e2123240..3be37e7ae3 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/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<ArraySubscriptExpr>(S), Pred, Dst);
+ VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(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/test/Analysis/vector.c b/test/Analysis/vector.m
index 32b568f6b0..e74c487d3a 100644
--- a/test/Analysis/vector.c
+++ b/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;
+}