mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[analyzer] Retrieve a value from list initialization of constant array declaration in a global scope.
Summary: Fix the point that we didn't take into account array's dimension. Retrieve a value of global constant array by iterating through its initializer list. Differential Revision: https://reviews.llvm.org/D104285 Fixes: https://bugs.llvm.org/show_bug.cgi?id=50604
This commit is contained in:
parent
5efafc3e65
commit
98a95d4844
@ -1668,23 +1668,50 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
|
||||
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
|
||||
// The array index has to be known.
|
||||
if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
|
||||
int64_t i = CI->getValue().getSExtValue();
|
||||
// If it is known that the index is out of bounds, we can return
|
||||
// an undefined value.
|
||||
if (i < 0)
|
||||
// If it is not an array, return Undef.
|
||||
QualType T = VD->getType();
|
||||
const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T);
|
||||
if (!CAT)
|
||||
return UndefinedVal();
|
||||
|
||||
if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
|
||||
if (CAT->getSize().sle(i))
|
||||
// Support one-dimensional array.
|
||||
// C++20 [expr.add] 7.6.6.4 (excerpt):
|
||||
// If P points to an array element i of an array object x with n
|
||||
// elements, where i < 0 or i > n, the behavior is undefined.
|
||||
// Dereferencing is not allowed on the "one past the last
|
||||
// element", when i == n.
|
||||
// Example:
|
||||
// const int arr[4] = {1, 2};
|
||||
// const int *ptr = arr;
|
||||
// int x0 = ptr[0]; // 1
|
||||
// int x1 = ptr[1]; // 2
|
||||
// int x2 = ptr[2]; // 0
|
||||
// int x3 = ptr[3]; // 0
|
||||
// int x4 = ptr[4]; // UB
|
||||
// TODO: Support multidimensional array.
|
||||
if (!isa<ConstantArrayType>(CAT->getElementType())) {
|
||||
// One-dimensional array.
|
||||
const llvm::APSInt &Idx = CI->getValue();
|
||||
const auto I = static_cast<uint64_t>(Idx.getExtValue());
|
||||
// Use `getZExtValue` because array extent can not be negative.
|
||||
const uint64_t Extent = CAT->getSize().getZExtValue();
|
||||
// Check for `Idx < 0`, NOT for `I < 0`, because `Idx` CAN be
|
||||
// negative, but `I` can NOT.
|
||||
if (Idx < 0 || I >= Extent)
|
||||
return UndefinedVal();
|
||||
|
||||
// If there is a list, but no init, it must be zero.
|
||||
if (i >= InitList->getNumInits())
|
||||
return svalBuilder.makeZeroVal(R->getElementType());
|
||||
// C++20 [expr.add] 9.4.17.5 (excerpt):
|
||||
// i-th array element is value-initialized for each k < i ≤ n,
|
||||
// where k is an expression-list size and n is an array extent.
|
||||
if (I >= InitList->getNumInits())
|
||||
return svalBuilder.makeZeroVal(R->getElementType());
|
||||
|
||||
if (const Expr *ElemInit = InitList->getInit(i))
|
||||
if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
|
||||
// Return a constant value, if it is presented.
|
||||
// FIXME: Support other SVals.
|
||||
const Expr *E = InitList->getInit(I);
|
||||
if (Optional<SVal> V = svalBuilder.getConstantVal(E))
|
||||
return *V;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-config eagerly-assume=false -analyzer-checker=core.uninitialized.Assign,debug.ExprInspection -verify %s
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
|
||||
@ -26,3 +26,74 @@ void multinit() {
|
||||
clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
const int glob_arr1[6] = {[2] = 3, [0] = 1, [1] = 2, [3] = 4};
|
||||
void glob_array_index1() {
|
||||
clang_analyzer_eval(glob_arr1[0] == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[1] == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[2] == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[3] == 4); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[4] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[5] == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
void glob_array_index2() {
|
||||
const int *ptr = glob_arr1;
|
||||
clang_analyzer_eval(ptr[0] == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[1] == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[2] == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[3] == 4); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[4] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[5] == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
void glob_invalid_index1() {
|
||||
int x = -42;
|
||||
int res = glob_arr1[x]; // expected-warning{{garbage or undefined}}
|
||||
}
|
||||
|
||||
void glob_invalid_index2() {
|
||||
const int *ptr = glob_arr1;
|
||||
int x = 42;
|
||||
int res = ptr[x]; // expected-warning{{garbage or undefined}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
const int glob_arr2[3][3] = {[0][0] = 1, [1][1] = 5, [2][0] = 7};
|
||||
void glob_arr_index3() {
|
||||
// FIXME: These all should be TRUE.
|
||||
clang_analyzer_eval(glob_arr2[0][0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[0][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[0][2] == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[1][0] == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[1][1] == 5); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[1][2] == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[2][0] == 7); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[2][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(glob_arr2[2][2] == 0); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void negative_index() {
|
||||
int x = 2, y = -2;
|
||||
// FIXME: Should be UNDEFINED.
|
||||
clang_analyzer_eval(glob_arr2[x][y] == 5); // expected-warning{{UNKNOWN}}
|
||||
x = 3;
|
||||
y = -3;
|
||||
// FIXME: Should be UNDEFINED.
|
||||
clang_analyzer_eval(glob_arr2[x][y] == 7); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index3() {
|
||||
int x = -1, y = -1;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
int res = glob_arr2[x][y]; // no-warning
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index4() {
|
||||
int x = 3, y = 2;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
int res = glob_arr2[x][y]; // no-warning
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -std=c++14 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
|
||||
// RUN: %clang_cc1 -std=c++14 -triple i386-apple-darwin10 -analyze -analyzer-config eagerly-assume=false -analyzer-checker=core.uninitialized.Assign,core.builtin,debug.ExprInspection,core.uninitialized.UndefReturn -verify %s
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
|
||||
@ -18,3 +18,113 @@ void arr2init() {
|
||||
// FIXME: Should recognize that it is 0.
|
||||
clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
int const glob_arr1[3] = {};
|
||||
void glob_array_index1() {
|
||||
clang_analyzer_eval(glob_arr1[0] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[1] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(glob_arr1[2] == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
void glob_invalid_index1() {
|
||||
const int *ptr = glob_arr1;
|
||||
int idx = -42;
|
||||
auto x = ptr[idx]; // expected-warning{{garbage or undefined}}
|
||||
}
|
||||
|
||||
int const glob_arr2[4] = {1, 2};
|
||||
void glob_ptr_index1() {
|
||||
int const *ptr = glob_arr2;
|
||||
clang_analyzer_eval(ptr[0] == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[1] == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[2] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[3] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNDEFINED}}
|
||||
}
|
||||
|
||||
void glob_invalid_index2() {
|
||||
const int *ptr = glob_arr2;
|
||||
int idx = 42;
|
||||
auto x = ptr[idx]; // expected-warning{{garbage or undefined}}
|
||||
}
|
||||
|
||||
const float glob_arr3[] = {
|
||||
0.0000, 0.0235, 0.0470, 0.0706, 0.0941, 0.1176};
|
||||
float no_warn_garbage_value() {
|
||||
return glob_arr3[0]; // no-warning (garbage or undefined)
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
int const glob_arr4[4][2] = {};
|
||||
void glob_array_index2() {
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr4[1][0] == 0); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr4[1][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index3() {
|
||||
int idx = -42;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
auto x = glob_arr4[1][idx]; // no-warning
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index4() {
|
||||
const int *ptr = glob_arr4[1];
|
||||
int idx = -42;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
auto x = ptr[idx]; // no-warning
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
int const glob_arr5[4][2] = {{1}, 3, 4, 5};
|
||||
void glob_array_index3() {
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[0][0] == 1); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[0][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[1][0] == 3); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[1][1] == 4); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[2][0] == 5); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[2][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[3][0] == 0); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(glob_arr5[3][1] == 0); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_ptr_index2() {
|
||||
int const *ptr = glob_arr5[1];
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(ptr[0] == 3); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(ptr[1] == 4); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be UNDEFINED.
|
||||
clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be UNDEFINED.
|
||||
clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: Should be UNDEFINED.
|
||||
clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index5() {
|
||||
int idx = -42;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
auto x = glob_arr5[1][idx]; // no-warning
|
||||
}
|
||||
|
||||
// TODO: Support multidimensional array.
|
||||
void glob_invalid_index6() {
|
||||
int const *ptr = &glob_arr5[1][0];
|
||||
int idx = 42;
|
||||
// FIXME: Should warn {{garbage or undefined}}.
|
||||
auto x = ptr[idx]; // // no-warning
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user