Skip to content

Commit 2d923a6

Browse files
author
MalavikaSamak
committed
[-Wunsafe-buffer-usage] Suppress warning for multi-dimensional constant arrays
Do not warn about unsafe buffer access, when multi-dimensional constant arrays are accessed and their indices are within the bounds of the buffer. Warning in such cases would be a false positive. Such a suppression already exists for 1-d arrays and it is now extended to multi-dimensional arrays. (rdar://137926311)
1 parent 7f19b1e commit 2d923a6

6 files changed

+88
-63
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,37 +433,36 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
433433
// already duplicated
434434
// - call both from Sema and from here
435435

436-
const auto *BaseDRE =
437-
dyn_cast<DeclRefExpr>(Node.getBase()->IgnoreParenImpCasts());
438-
const auto *SLiteral =
439-
dyn_cast<StringLiteral>(Node.getBase()->IgnoreParenImpCasts());
440-
uint64_t size;
441-
442-
if (!BaseDRE && !SLiteral)
443-
return false;
444-
445-
if (BaseDRE) {
446-
if (!BaseDRE->getDecl())
447-
return false;
448-
const auto *CATy = Finder->getASTContext().getAsConstantArrayType(
449-
BaseDRE->getDecl()->getType());
450-
if (!CATy) {
436+
std::function<bool(const ArraySubscriptExpr *)> CheckBounds =
437+
[&CheckBounds](const ArraySubscriptExpr *ASE) -> bool {
438+
uint64_t limit;
439+
if (const auto *CATy =
440+
dyn_cast<ConstantArrayType>(ASE->getBase()
441+
->IgnoreParenImpCasts()
442+
->getType()
443+
->getUnqualifiedDesugaredType())) {
444+
limit = CATy->getLimitedSize();
445+
} else if (const auto *SLiteral = dyn_cast<StringLiteral>(
446+
ASE->getBase()->IgnoreParenImpCasts())) {
447+
limit = SLiteral->getLength() + 1;
448+
} else {
451449
return false;
452450
}
453-
size = CATy->getLimitedSize();
454-
} else if (SLiteral) {
455-
size = SLiteral->getLength() + 1;
456-
}
457451

458-
if (const auto *IdxLit = dyn_cast<IntegerLiteral>(Node.getIdx())) {
459-
const APInt ArrIdx = IdxLit->getValue();
460-
// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a
461-
// bug
462-
if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < size)
452+
if (const auto *IdxLit = dyn_cast<IntegerLiteral>(ASE->getIdx())) {
453+
const APInt ArrIdx = IdxLit->getValue();
454+
if (!ArrIdx.isNonNegative() || ArrIdx.getLimitedValue() >= limit)
455+
return false;
456+
if (const auto *BaseASE = dyn_cast<ArraySubscriptExpr>(
457+
ASE->getBase()->IgnoreParenImpCasts())) {
458+
return CheckBounds(BaseASE);
459+
}
463460
return true;
464-
}
461+
}
462+
return false;
463+
};
465464

466-
return false;
465+
return CheckBounds(&Node);
467466
}
468467

469468
AST_MATCHER_P(CallExpr, hasNumArgs, unsigned, Num) {
@@ -1172,6 +1171,12 @@ class ArraySubscriptGadget : public WarningGadget {
11721171
if (const auto *DRE =
11731172
dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
11741173
return {DRE};
1174+
} else if (const auto *BaseASE = dyn_cast<ArraySubscriptExpr>(
1175+
ASE->getBase()->IgnoreParenImpCasts())) {
1176+
if (const auto *DRE = dyn_cast<DeclRefExpr>(
1177+
BaseASE->getBase()->IgnoreParenImpCasts())) {
1178+
return {DRE};
1179+
}
11751180
}
11761181

11771182
return {};

clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,37 @@ void constant_id_string(unsigned idx) {
5252
unsafe_char = ""[1]; //expected-warning{{unsafe buffer access}}
5353
unsafe_char = ""[idx]; //expected-warning{{unsafe buffer access}}
5454
}
55+
56+
typedef float Float4x4[4][4];
57+
58+
// expected-warning@+1 {{'matrix' is an unsafe buffer that does not perform bounds checks}}
59+
float two_dimension_array(Float4x4& matrix) {
60+
// expected-note@+1{{used in buffer access here}}
61+
float a = matrix[0][4];
62+
63+
a = matrix[0][3];
64+
65+
// expected-note@+1{{used in buffer access here}}
66+
a = matrix[4][0];
67+
68+
return matrix[1][1];
69+
}
70+
71+
typedef float Float2x3x4[2][3][4];
72+
float multi_dimension_array(Float2x3x4& matrix) {
73+
float *f = matrix[0][2];
74+
return matrix[1][2][3];
75+
}
76+
77+
char array_strings[][11] = {
78+
"Apple", "Banana", "Cherry", "Date", "Elderberry"
79+
};
80+
81+
char array_string[] = "123456";
82+
83+
char access_strings() {
84+
char c = array_strings[0][4];
85+
c = array_strings[3][10];
86+
c = array_string[5];
87+
return c;
88+
}

clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ void test_attribute_multiple_fields (D d) {
9696

9797
int v = d.buf[0]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
9898

99-
//expected-warning@+1{{unsafe buffer access}}
10099
v = d.buf[5]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
101100
}
102101

clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-main.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@
88
// main function
99
int main(int argc, char *argv[]) { // expected-warning{{'argv' is an unsafe pointer used for buffer access}}
1010
char tmp;
11-
tmp = argv[5][5]; // expected-note{{used in buffer access here}} \
12-
expected-warning{{unsafe buffer access}}
11+
tmp = argv[5][5]; // expected-note2{{used in buffer access here}}
1312
}

clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) {
118118
// expected-warning@-2{{'b' is an unsafe pointer used for buffer access}}
119119
int tmp;
120120

121-
tmp = a[5][5] + b[5][5]; // expected-warning2{{unsafe buffer access}} expected-note2{{used in buffer access here}}
121+
tmp = a[5][5] + b[5][5]; // expected-note4{{used in buffer access here}}
122122
}
123123

124124
// parameter having default values:

clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,9 @@ void testArraySubscripts(int idx, int *p, int **pp) {
4040
// expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
4141
// expected-warning@-2{{'pp' is an unsafe pointer used for buffer access}}
4242
foo(p[1], // expected-note{{used in buffer access here}}
43-
pp[1][1], // expected-note{{used in buffer access here}}
44-
// expected-warning@-1{{unsafe buffer access}}
45-
1[1[pp]], // expected-note{{used in buffer access here}}
46-
// expected-warning@-1{{unsafe buffer access}}
47-
1[pp][1] // expected-note{{used in buffer access here}}
48-
// expected-warning@-1{{unsafe buffer access}}
43+
pp[1][1], // expected-note2{{used in buffer access here}}
44+
1[1[pp]], // expected-note2{{used in buffer access here}}
45+
1[pp][1] // expected-note2{{used in buffer access here}}
4946
);
5047

5148
if (p[3]) { // expected-note{{used in buffer access here}}
@@ -65,13 +62,9 @@ void testArraySubscripts(int idx, int *p, int **pp) {
6562
int b[10][10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}}
6663

6764
foo(a[idx], idx[a], // expected-note2{{used in buffer access here}}
68-
b[idx][idx + 1], // expected-warning{{unsafe buffer access}}
69-
// expected-note@-1{{used in buffer access here}}
70-
(idx + 1)[b][idx],// expected-warning{{unsafe buffer access}}
71-
// expected-note@-1{{used in buffer access here}}
72-
(idx + 1)[idx[b]]);
73-
// expected-warning@-1{{unsafe buffer access}}
74-
// expected-note@-2{{used in buffer access here}}
65+
b[idx][idx + 1], // expected-note2{{used in buffer access here}}
66+
(idx + 1)[b][idx],// expected-note2{{used in buffer access here}}
67+
(idx + 1)[idx[b]]); // expected-note2{{used in buffer access here}}
7568

7669
// Not to warn when index is zero
7770
foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0],
@@ -108,8 +101,7 @@ void testQualifiedParameters(const int * p, const int * const q, const int a[10]
108101
foo(p[1], 1[p], p[-1], // expected-note3{{used in buffer access here}}
109102
q[1], 1[q], q[-1], // expected-note3{{used in buffer access here}}
110103
a[1], // expected-note{{used in buffer access here}} `a` is of pointer type
111-
b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type
112-
// expected-warning@-1{{unsafe buffer access}}
104+
b[1][2] // expected-note2{{used in buffer access here}} `b[1]` is of array type
113105
);
114106
}
115107

@@ -128,25 +120,25 @@ T_t funRetT();
128120
T_t * funRetTStar();
129121

130122
void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) {
131-
foo(sp->a[1], // expected-warning{{unsafe buffer access}}
123+
foo(sp->a[1],
132124
sp->b[1], // expected-warning{{unsafe buffer access}}
133-
sp->c.a[1], // expected-warning{{unsafe buffer access}}
125+
sp->c.a[1],
134126
sp->c.b[1], // expected-warning{{unsafe buffer access}}
135-
s.a[1], // expected-warning{{unsafe buffer access}}
127+
s.a[1],
136128
s.b[1], // expected-warning{{unsafe buffer access}}
137-
s.c.a[1], // expected-warning{{unsafe buffer access}}
129+
s.c.a[1],
138130
s.c.b[1], // expected-warning{{unsafe buffer access}}
139-
sp2->a[1], // expected-warning{{unsafe buffer access}}
131+
sp2->a[1],
140132
sp2->b[1], // expected-warning{{unsafe buffer access}}
141-
sp2->c.a[1], // expected-warning{{unsafe buffer access}}
133+
sp2->c.a[1],
142134
sp2->c.b[1], // expected-warning{{unsafe buffer access}}
143-
s2.a[1], // expected-warning{{unsafe buffer access}}
135+
s2.a[1],
144136
s2.b[1], // expected-warning{{unsafe buffer access}}
145-
s2.c.a[1], // expected-warning{{unsafe buffer access}}
137+
s2.c.a[1],
146138
s2.c.b[1], // expected-warning{{unsafe buffer access}}
147-
funRetT().a[1], // expected-warning{{unsafe buffer access}}
139+
funRetT().a[1],
148140
funRetT().b[1], // expected-warning{{unsafe buffer access}}
149-
funRetTStar()->a[1], // expected-warning{{unsafe buffer access}}
141+
funRetTStar()->a[1],
150142
funRetTStar()->b[1] // expected-warning{{unsafe buffer access}}
151143
);
152144
}
@@ -213,7 +205,6 @@ void testTypedefs(T_ptr_t p) {
213205
// expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
214206
foo(p[1], // expected-note{{used in buffer access here}}
215207
p[1].a[1], // expected-note{{used in buffer access here}}
216-
// expected-warning@-1{{unsafe buffer access}}
217208
p[1].b[1] // expected-note{{used in buffer access here}}
218209
// expected-warning@-1{{unsafe buffer access}}
219210
);
@@ -223,10 +214,9 @@ template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) {
223214
// expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}
224215
// expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}}
225216
// expected-warning@-3{{'a' is an unsafe pointer used for buffer access}}
226-
// expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}}
227217
foo(pt[1], // expected-note{{used in buffer access here}}
228218
a[1], // expected-note{{used in buffer access here}}
229-
b[1]); // expected-note{{used in buffer access here}}
219+
b[1]);
230220
return &t[1]; // expected-note{{used in buffer access here}}
231221
}
232222

@@ -366,17 +356,15 @@ int testArrayAccesses(int n, int idx) {
366356
// expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}}
367357
int d = cArr[0][0];
368358
foo(cArr[0][0]);
369-
foo(cArr[idx][idx + 1]); // expected-note{{used in buffer access here}}
370-
// expected-warning@-1{{unsafe buffer access}}
371-
auto cPtr = cArr[idx][idx * 2]; // expected-note{{used in buffer access here}}
372-
// expected-warning@-1{{unsafe buffer access}}
359+
foo(cArr[idx][idx + 1]); // expected-note2{{used in buffer access here}}
360+
auto cPtr = cArr[idx][idx * 2]; // expected-note2{{used in buffer access here}}
373361
foo(cPtr);
374362

375363
// Typdefs
376364
typedef int A[3];
377365
const A tArr = {4, 5, 6};
378366
foo(tArr[0], tArr[1]);
379-
return cArr[0][1]; // expected-warning{{unsafe buffer access}}
367+
return cArr[0][1];
380368
}
381369

382370
void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}}

0 commit comments

Comments
 (0)