forked from OSchip/llvm-project
[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
This commit is contained in:
parent
d495301414
commit
8d345cb8a5
|
@ -332,9 +332,9 @@ public:
|
||||||
void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
|
void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
|
||||||
|
|
||||||
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
||||||
void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex,
|
void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex,
|
||||||
ExplodedNode *Pred,
|
ExplodedNode *Pred,
|
||||||
ExplodedNodeSet &Dst);
|
ExplodedNodeSet &Dst);
|
||||||
|
|
||||||
/// VisitGCCAsmStmt - Transfer function logic for inline asm.
|
/// VisitGCCAsmStmt - Transfer function logic for inline asm.
|
||||||
void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
|
void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
||||||
|
|
||||||
case Stmt::ArraySubscriptExprClass:
|
case Stmt::ArraySubscriptExprClass:
|
||||||
Bldr.takeNodes(Pred);
|
Bldr.takeNodes(Pred);
|
||||||
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
|
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
|
||||||
Bldr.addNodes(Dst);
|
Bldr.addNodes(Dst);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2126,10 +2126,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// VisitArraySubscriptExpr - Transfer function for array accesses
|
/// VisitArraySubscriptExpr - Transfer function for array accesses
|
||||||
void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
|
void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
|
||||||
ExplodedNode *Pred,
|
ExplodedNode *Pred,
|
||||||
ExplodedNodeSet &Dst){
|
ExplodedNodeSet &Dst){
|
||||||
|
|
||||||
const Expr *Base = A->getBase()->IgnoreParens();
|
const Expr *Base = A->getBase()->IgnoreParens();
|
||||||
const Expr *Idx = A->getIdx()->IgnoreParens();
|
const Expr *Idx = A->getIdx()->IgnoreParens();
|
||||||
|
|
||||||
|
@ -2138,18 +2137,32 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
|
||||||
|
|
||||||
ExplodedNodeSet EvalSet;
|
ExplodedNodeSet EvalSet;
|
||||||
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
|
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
|
||||||
assert(A->isGLValue() ||
|
|
||||||
(!AMgr.getLangOpts().CPlusPlus &&
|
bool IsVectorType = A->getBase()->getType()->isVectorType();
|
||||||
A->getType().isCForbiddenLValueType()));
|
|
||||||
|
// 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) {
|
for (auto *Node : CheckerPreStmt) {
|
||||||
const LocationContext *LCtx = Node->getLocationContext();
|
const LocationContext *LCtx = Node->getLocationContext();
|
||||||
ProgramStateRef state = Node->getState();
|
ProgramStateRef state = Node->getState();
|
||||||
SVal V = state->getLValue(A->getType(),
|
|
||||||
state->getSVal(Idx, LCtx),
|
if (IsGLValueLike) {
|
||||||
state->getSVal(Base, LCtx));
|
SVal V = state->getLValue(A->getType(),
|
||||||
Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr,
|
state->getSVal(Idx, LCtx),
|
||||||
ProgramPoint::PostLValueKind);
|
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);
|
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
typedef int __attribute__((ext_vector_type(2))) V;
|
typedef int __attribute__((ext_vector_type(2))) V;
|
||||||
|
|
||||||
|
void clang_analyzer_warnIfReached();
|
||||||
void clang_analyzer_numTimesReached();
|
void clang_analyzer_numTimesReached();
|
||||||
void clang_analyzer_eval(int);
|
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}}
|
clang_analyzer_numTimesReached(); // expected-warning{{2}}
|
||||||
return z;
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue