Files
Endre FülöpandDonát Nagy 5ddae7ae33 [analyzer] Generalize field initializer resolution in RegionStore (#189361)
Replace the ad-hoc blocks in getBindingForField with a single helper
getConstantValFromInitializer that walks up the region chain to a
VarRegion, then walks down the InitListExpr (semantic form) by field
and element indices. Handles arbitrary nesting depth, including
multidimensional arrays of structs and structs containing arrays.

The same trust conditions apply: const-qualified types are always
trusted, and non-const globals are trusted when analyzing main().
For C++ structs with user-defined constructors, we conservatively
fall through to the symbolic path because the constructor body may
establish values that differ from the InitListExpr. Resolving
constructor-initialized values is left to a separate change.

Union initializers are handled by matching the accessed field against
the initialized member, accesses to inactive union members return
unknown.

This resolves false positives from security.ArrayBound on
sentinel-terminated struct arrays and fixes a FIXME where
CXXDefaultInitExpr in const arrays was not recognized.

---------

Co-authored-by: Donát Nagy <donat.nagy@ericsson.com>
2026-06-07 18:35:33 +02:00

341 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// RUN: %clang_analyze_cc1 -std=c++14 -triple i386-apple-darwin10 -analyzer-config eagerly-assume=false -analyzer-checker=core.uninitialized.Assign,core.builtin,debug.ExprInspection,core.uninitialized.UndefReturn -verify %s
template <typename T>
void clang_analyzer_dump(T x);
void clang_analyzer_eval(int);
struct S {
int a = 3;
};
S const sarr[2] = {};
void definit() {
int i = 1;
clang_analyzer_dump(sarr[i].a); // expected-warning{{3 S32b}}
}
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{{uninitialized}}
}
void glob_symbolic_index1(int idx) {
clang_analyzer_dump(glob_arr1[idx]); // expected-warning{{Unknown}}
}
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{{uninitialized}}
}
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 (not meaningful)
}
int const glob_arr4[4][2] = {};
void glob_array_index2() {
clang_analyzer_eval(glob_arr4[0][0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr4[1][0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr4[1][1] == 0); // expected-warning{{TRUE}}
}
void glob_invalid_index3() {
int idx = -42;
auto x = glob_arr4[1][idx]; // expected-warning{{uninitialized}}
}
void glob_invalid_index4() {
const int *ptr = glob_arr4[1];
int idx = -42;
auto x = ptr[idx]; // expected-warning{{uninitialized}}
}
int const glob_arr5[4][2] = {{1}, 3, 4, 5};
void glob_array_index3() {
clang_analyzer_eval(glob_arr5[0][0] == 1); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[0][1] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[1][0] == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[1][1] == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[2][0] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[2][1] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[3][0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr5[3][1] == 0); // expected-warning{{TRUE}}
}
void glob_ptr_index2() {
int const *ptr = glob_arr5[1];
clang_analyzer_eval(ptr[0] == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[1] == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[2] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[3] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[4] == 0); // expected-warning{{TRUE}}
}
void glob_invalid_index5() {
int idx = -42;
auto x = glob_arr5[1][idx]; // expected-warning{{uninitialized}}
}
void glob_invalid_index6() {
int const *ptr = &glob_arr5[1][0];
int idx = 42;
auto x = ptr[idx]; // expected-warning{{uninitialized}}
}
extern const int glob_arr_no_init[10];
void glob_array_index4() {
clang_analyzer_eval(glob_arr_no_init[2]); // expected-warning{{UNKNOWN}}
}
struct S2 {
static const int arr_no_init[10];
};
void struct_arr_index1() {
clang_analyzer_eval(S2::arr_no_init[2]); // expected-warning{{UNKNOWN}}
}
char const glob_arr6[5] = "123";
void glob_array_index5() {
clang_analyzer_eval(glob_arr6[0] == '1'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr6[1] == '2'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr6[2] == '3'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr6[3] == '\0'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr6[4] == '\0'); // expected-warning{{TRUE}}
}
void glob_ptr_index3() {
char const *ptr = glob_arr6;
clang_analyzer_eval(ptr[-42] == '\0'); // expected-warning{{UNDEFINED}}
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] == '\0'); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[4] == '\0'); // expected-warning{{TRUE}}
clang_analyzer_eval(ptr[5] == '\0'); // expected-warning{{UNDEFINED}}
clang_analyzer_eval(ptr[6] == '\0'); // expected-warning{{UNDEFINED}}
}
void glob_invalid_index7() {
int idx = -42;
auto x = glob_arr6[idx]; // expected-warning{{uninitialized}}
}
void glob_invalid_index8() {
const char *ptr = glob_arr6;
int idx = 42;
auto x = ptr[idx]; // expected-warning{{uninitialized}}
}
char const glob_arr7[5] = {"123"};
void glob_array_index6() {
clang_analyzer_eval(glob_arr7[0] == '1'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr7[1] == '2'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr7[2] == '3'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr7[3] == '\0'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr7[4] == '\0'); // expected-warning{{TRUE}}
}
void glob_invalid_index9() {
int idx = -42;
auto x = glob_arr7[idx]; // expected-warning{{uninitialized}}
}
void glob_invalid_index10() {
const char *ptr = glob_arr7;
int idx = 42;
auto x = ptr[idx]; // expected-warning{{uninitialized}}
}
char const *const glob_ptr8 = "123";
void glob_ptr_index4() {
clang_analyzer_eval(glob_ptr8[0] == '1'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr8[1] == '2'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr8[2] == '3'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr8[3] == '\0'); // expected-warning{{TRUE}}
// FIXME: Should be UNDEFINED.
// We should take into account a declaration in which the literal is used.
clang_analyzer_eval(glob_ptr8[4] == '\0'); // expected-warning{{TRUE}}
}
void glob_invalid_index11() {
int idx = -42;
auto x = glob_ptr8[idx]; // expected-warning{{uninitialized}}
}
void glob_invalid_index12() {
int idx = 42;
// FIXME: Should warn {{uninitialized}}
// We should take into account a declaration in which the literal is used.
auto x = glob_ptr8[idx]; // no-warning
}
const char16_t *const glob_ptr9 = u"абв";
void glob_ptr_index5() {
clang_analyzer_eval(glob_ptr9[0] == u'а'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr9[1] == u'б'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr9[2] == u'в'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr9[3] == '\0'); // expected-warning{{TRUE}}
}
const char32_t *const glob_ptr10 = U"\U0001F607\U0001F608\U0001F609";
void glob_ptr_index6() {
clang_analyzer_eval(glob_ptr10[0] == U'\U0001F607'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr10[1] == U'\U0001F608'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr10[2] == U'\U0001F609'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr10[3] == '\0'); // expected-warning{{TRUE}}
}
const wchar_t *const glob_ptr11 = L"\123\u0041\xFF";
void glob_ptr_index7() {
clang_analyzer_eval(glob_ptr11[0] == L'\123'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr11[1] == L'\u0041'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr11[2] == L'\xFF'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr11[3] == L'\0'); // expected-warning{{TRUE}}
}
const char *const glob_ptr12 = u8"abc";
void glob_ptr_index8() {
clang_analyzer_eval(glob_ptr12[0] == 'a'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr12[1] == 'b'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr12[2] == 'c'); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_ptr12[3] == '\0'); // expected-warning{{TRUE}}
}
typedef int Int;
typedef Int const CInt;
typedef CInt Arr[2];
typedef Arr Arr2[4];
Arr2 glob_arr8 = {{1}, 3, 4, 5}; // const int[4][2]
void glob_array_typedef1() {
clang_analyzer_eval(glob_arr8[0][0] == 1); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[0][1] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[1][0] == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[1][1] == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[2][0] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[2][1] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[3][0] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr8[3][1] == 0); // expected-warning{{TRUE}}
}
const int glob_arr9[2][4] = {{(1), 2, ((3)), 4}, 5, 6, (((7)))};
void glob_array_parentheses1() {
clang_analyzer_eval(glob_arr9[0][0] == 1); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[0][1] == 2); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[0][2] == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[0][3] == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[1][0] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[1][1] == 6); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[1][2] == 7); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[1][3] == 0); // expected-warning{{TRUE}}
}
enum class E {};
const E glob[] = {{}};
void initlistWithinInitlist() {
// no-crash
clang_analyzer_dump(glob[0]); // expected-warning-re {{reg_${{[0-9]+}}<enum E Element{glob,0 S64b,enum E}>}}
}
const int glob_arr_cross[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
void glob_array_cross_subarray_boundary() {
const int *p = &glob_arr_cross[0][0];
clang_analyzer_eval(p[4] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(p[7] == 8); // expected-warning{{TRUE}}
clang_analyzer_eval(p[11] == 12); // expected-warning{{TRUE}}
}
const int glob_arr_sparse[4][3] = {{1, 2}, {0, 0, 7}};
void glob_array_sparse_cross_boundary() {
const int *p = &glob_arr_sparse[0][0];
clang_analyzer_eval(p[0] == 1); // expected-warning{{TRUE}}
clang_analyzer_eval(p[1] == 2); // expected-warning{{TRUE}}
clang_analyzer_eval(p[2] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[3] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[5] == 7); // expected-warning{{TRUE}}
clang_analyzer_eval(p[6] == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[11] == 0); // expected-warning{{TRUE}}
}
const int glob_arr_3d[2][3][4] = {
{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}};
void glob_array_3d_cross_boundary() {
const int *p = &glob_arr_3d[0][0][0];
clang_analyzer_eval(p[0] == 1); // expected-warning{{TRUE}}
clang_analyzer_eval(p[5] == 6); // expected-warning{{TRUE}}
clang_analyzer_eval(p[11] == 12); // expected-warning{{TRUE}}
clang_analyzer_eval(p[12] == 13); // expected-warning{{TRUE}}
clang_analyzer_eval(p[23] == 24); // expected-warning{{TRUE}}
}
// Limitation: type-punned access through incompatible pointer type.
const int glob_arr_pun[2][3] = {{1, 2, 3}, {4, 5, 6}};
void glob_array_type_pun_unresolved() {
const unsigned *p = (const unsigned *)&glob_arr_pun[0][0];
clang_analyzer_dump(p[0]); // expected-warning-re{{reg_${{[0-9]+}}<unsigned int Element{glob_arr_pun,0 S64b,unsigned int}>}}
}
const int glob_arr_recast[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
void glob_array_recast_resolves_against_declared_type() {
const int (*q)[6] = (const int (*)[6])&glob_arr_recast[0][0];
clang_analyzer_eval(q[0][4] == 5); // expected-warning{{TRUE}}
clang_analyzer_eval(q[1][0] == 4); // expected-warning{{TRUE}}
}
void glob_array_write_then_read_cross_boundary() {
int arr[4][3];
arr[0][0] = 10;
arr[1][1] = 42;
arr[2][2] = 99;
arr[3][2] = 77;
int *p = &arr[0][0];
clang_analyzer_eval(p[0] == 10); // expected-warning{{TRUE}}
clang_analyzer_eval(p[4] == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(p[8] == 99); // expected-warning{{TRUE}}
clang_analyzer_eval(p[11] == 77); // expected-warning{{TRUE}}
}
void glob_array_write_then_read_before_start() {
int arr[4][3];
arr[0][0] = 10;
int *p = &arr[0][0];
int x = p[-1]; // expected-warning{{Assigned value is uninitialized}}
(void)x;
}
// Negative inner index from a non-zero outer base lands within the allocation.
const int glob_arr_neg[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
void glob_array_negative_inner_index() {
const int *p = &glob_arr_neg[2][0];
clang_analyzer_eval(p[-1] == 6); // expected-warning{{TRUE}}
}
void glob_array_write_then_read_past_end() {
int arr[4][3];
arr[3][2] = 77;
int *p = &arr[0][0];
int x = p[12]; // expected-warning{{Assigned value is uninitialized}}
(void)x;
}