mirror of https://github.com/microsoft/clang.git
[analyzer] const init: handle non-explicit cases more accurately
Summary: If the access is out of bounds, return UndefinedVal. If it is missing an explicit init, return the implicit zero value it must have. Reviewers: NoQ, xazax.hun, george.karpenkov Reviewed By: NoQ Subscribers: szepet, rnkovacs, a.sidorin, cfe-commits Differential Revision: https://reviews.llvm.org/D46823 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333417 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c01eff1a9b
commit
29dd917851
|
@ -1638,9 +1638,18 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
|
||||||
// The array index has to be known.
|
// The array index has to be known.
|
||||||
if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
|
if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
|
||||||
int64_t i = CI->getValue().getSExtValue();
|
int64_t i = CI->getValue().getSExtValue();
|
||||||
// Return unknown value if index is out of bounds.
|
// If it is known that the index is out of bounds, we can return
|
||||||
if (i < 0 || i >= InitList->getNumInits())
|
// an undefined value.
|
||||||
return UnknownVal();
|
if (i < 0)
|
||||||
|
return UndefinedVal();
|
||||||
|
|
||||||
|
if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
|
||||||
|
if (CAT->getSize().sle(i))
|
||||||
|
return UndefinedVal();
|
||||||
|
|
||||||
|
// If there is a list, but no init, it must be zero.
|
||||||
|
if (i >= InitList->getNumInits())
|
||||||
|
return svalBuilder.makeZeroVal(R->getElementType());
|
||||||
|
|
||||||
if (const Expr *ElemInit = InitList->getInit(i))
|
if (const Expr *ElemInit = InitList->getInit(i))
|
||||||
if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
|
if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
|
||||||
|
@ -1715,11 +1724,15 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
|
||||||
// Either the record variable or the field has to be const qualified.
|
// Either the record variable or the field has to be const qualified.
|
||||||
if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
|
if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
|
||||||
if (const Expr *Init = VD->getInit())
|
if (const Expr *Init = VD->getInit())
|
||||||
if (const auto *InitList = dyn_cast<InitListExpr>(Init))
|
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
|
||||||
if (Index < InitList->getNumInits())
|
if (Index < InitList->getNumInits()) {
|
||||||
if (const Expr *FieldInit = InitList->getInit(Index))
|
if (const Expr *FieldInit = InitList->getInit(Index))
|
||||||
if (Optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
|
if (Optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
|
||||||
return *V;
|
return *V;
|
||||||
|
} else {
|
||||||
|
return svalBuilder.makeZeroVal(Ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBindingForFieldOrElementCommon(B, R, Ty);
|
return getBindingForFieldOrElementCommon(B, R, Ty);
|
||||||
|
|
|
@ -1,7 +1,28 @@
|
||||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
|
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
|
||||||
// expected-no-diagnostics
|
|
||||||
|
void clang_analyzer_eval(int);
|
||||||
|
|
||||||
void initbug() {
|
void initbug() {
|
||||||
const union { float a; } u = {};
|
const union { float a; } u = {};
|
||||||
(void)u.a; // no-crash
|
(void)u.a; // no-crash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int const parr[2] = {1};
|
||||||
|
void constarr() {
|
||||||
|
int i = 2;
|
||||||
|
clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
|
||||||
|
i = 1;
|
||||||
|
clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
|
||||||
|
i = -1;
|
||||||
|
clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SM {
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
const struct SM sm = {.a = 1};
|
||||||
|
void multinit() {
|
||||||
|
clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
|
||||||
|
clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
|
||||||
|
|
||||||
|
void clang_analyzer_eval(int);
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
int a = 3;
|
||||||
|
};
|
||||||
|
S const sarr[2] = {};
|
||||||
|
void definit() {
|
||||||
|
int i = 1;
|
||||||
|
// FIXME: Should recognize that it is 3.
|
||||||
|
clang_analyzer_eval(sarr[i].a); // expected-warning{{UNKNOWN}}
|
||||||
|
}
|
||||||
|
|
||||||
|
int const arr[2][2] = {};
|
||||||
|
void arr2init() {
|
||||||
|
int i = 1;
|
||||||
|
// FIXME: Should recognize that it is 0.
|
||||||
|
clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
|
||||||
|
}
|
Loading…
Reference in New Issue