Skip to content

Commit 8d345cb

Browse files
author
George Karpenkov
committedDec 5, 2017
[analyzer] do not crash on cases where an array subscript is an rvalue
Array subscript is almost always an lvalue, except for a few cases where it is not, such as a subscript into an Objective-C property, or a return from the function. This commit prevents crashing in such cases. Fixes rdar://34829842 Differential Revision: https://reviews.llvm.org/D40584 llvm-svn: 319834
1 parent d495301 commit 8d345cb

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed
 

‎clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,9 @@ class ExprEngine : public SubEngine {
332332
void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
333333

334334
/// VisitArraySubscriptExpr - Transfer function for array accesses.
335-
void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex,
336-
ExplodedNode *Pred,
337-
ExplodedNodeSet &Dst);
335+
void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex,
336+
ExplodedNode *Pred,
337+
ExplodedNodeSet &Dst);
338338

339339
/// VisitGCCAsmStmt - Transfer function logic for inline asm.
340340
void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,

‎clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
11501150

11511151
case Stmt::ArraySubscriptExprClass:
11521152
Bldr.takeNodes(Pred);
1153-
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
1153+
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
11541154
Bldr.addNodes(Dst);
11551155
break;
11561156

@@ -2126,10 +2126,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
21262126
}
21272127

21282128
/// VisitArraySubscriptExpr - Transfer function for array accesses
2129-
void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
2129+
void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
21302130
ExplodedNode *Pred,
21312131
ExplodedNodeSet &Dst){
2132-
21332132
const Expr *Base = A->getBase()->IgnoreParens();
21342133
const Expr *Idx = A->getIdx()->IgnoreParens();
21352134

@@ -2138,18 +2137,32 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
21382137

21392138
ExplodedNodeSet EvalSet;
21402139
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
2141-
assert(A->isGLValue() ||
2142-
(!AMgr.getLangOpts().CPlusPlus &&
2143-
A->getType().isCForbiddenLValueType()));
2140+
2141+
bool IsVectorType = A->getBase()->getType()->isVectorType();
2142+
2143+
// The "like" case is for situations where C standard prohibits the type to
2144+
// be an lvalue, e.g. taking the address of a subscript of an expression of
2145+
// type "void *".
2146+
bool IsGLValueLike = A->isGLValue() ||
2147+
(A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
21442148

21452149
for (auto *Node : CheckerPreStmt) {
21462150
const LocationContext *LCtx = Node->getLocationContext();
21472151
ProgramStateRef state = Node->getState();
2148-
SVal V = state->getLValue(A->getType(),
2149-
state->getSVal(Idx, LCtx),
2150-
state->getSVal(Base, LCtx));
2151-
Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr,
2152-
ProgramPoint::PostLValueKind);
2152+
2153+
if (IsGLValueLike) {
2154+
SVal V = state->getLValue(A->getType(),
2155+
state->getSVal(Idx, LCtx),
2156+
state->getSVal(Base, LCtx));
2157+
Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr,
2158+
ProgramPoint::PostLValueKind);
2159+
} else if (IsVectorType) {
2160+
// FIXME: non-glvalue vector reads are not modelled.
2161+
Bldr.generateNode(A, Node, state, nullptr);
2162+
} else {
2163+
llvm_unreachable("Array subscript should be an lValue when not \
2164+
a vector and not a forbidden lvalue type");
2165+
}
21532166
}
21542167

21552168
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);

‎clang/test/Analysis/vector.c renamed to ‎clang/test/Analysis/vector.m

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
typedef int __attribute__((ext_vector_type(2))) V;
44

5+
void clang_analyzer_warnIfReached();
56
void clang_analyzer_numTimesReached();
67
void clang_analyzer_eval(int);
78

@@ -26,3 +27,35 @@ V dont_crash_and_dont_split_state(V x, V y) {
2627
clang_analyzer_numTimesReached(); // expected-warning{{2}}
2728
return z;
2829
}
30+
31+
void test_read() {
32+
V x;
33+
x[0] = 0;
34+
x[1] = 1;
35+
36+
clang_analyzer_eval(x[0] == 0); // expected-warning{{TRUE}}
37+
}
38+
39+
V return_vector() {
40+
V z;
41+
z[0] = 0;
42+
z[1] = 0;
43+
return z;
44+
}
45+
46+
int test_vector_access() {
47+
return return_vector()[0]; // no-crash no-warning
48+
}
49+
50+
@interface I
51+
@property V v;
52+
@end
53+
54+
// Do not crash on subscript operations into ObjC properties.
55+
int myfunc(I *i2) {
56+
int out = i2.v[0]; // no-crash no-warning
57+
58+
// Check that the analysis continues.
59+
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
60+
return out;
61+
}

0 commit comments

Comments
 (0)
Please sign in to comment.