Skip to content

Commit ab9cd53

Browse files
malavikasamakMalavikaSamak
andauthored
[Wunsafe-buffer-usage] False positives for & expression indexing constant size array (arr[anything & 0]) (#112284)
Do not warn when a constant sized array is indexed with an expression that contains bitwise and operation involving constants and it always results in a bound safe access. (rdar://136684050) --------- Co-authored-by: MalavikaSamak <[email protected]>
1 parent 69cc16f commit ab9cd53

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,25 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
462462
// bug
463463
if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
464464
return true;
465+
} else if (const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
466+
// For an integer expression `e` and an integer constant `n`, `e & n` and
467+
// `n & e` are bounded by `n`:
468+
if (BE->getOpcode() != BO_And)
469+
return false;
470+
471+
const Expr *LHS = BE->getLHS();
472+
const Expr *RHS = BE->getRHS();
473+
474+
if ((!LHS->isValueDependent() &&
475+
LHS->EvaluateAsInt(EVResult,
476+
Finder->getASTContext())) || // case: `n & e`
477+
(!RHS->isValueDependent() &&
478+
RHS->EvaluateAsInt(EVResult, Finder->getASTContext()))) { // `e & n`
479+
llvm::APSInt result = EVResult.Val.getInt();
480+
if (result.isNonNegative() && result.getLimitedValue() < limit)
481+
return true;
482+
}
483+
return false;
465484
}
466485
return false;
467486
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ void foo2(unsigned idx) {
1818

1919
struct Foo {
2020
int member_buffer[10];
21+
int x;
2122
};
23+
2224
void foo2(Foo& f, unsigned idx) {
2325
f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}}
2426
}
@@ -33,6 +35,37 @@ void constant_idx_safe0(unsigned idx) {
3335
buffer[0] = 0;
3436
}
3537

38+
int array[10]; // expected-warning {{'array' is an unsafe buffer that does not perform bounds checks}}
39+
40+
void masked_idx1(unsigned long long idx, Foo f) {
41+
// Bitwise and operation
42+
array[idx & 5] = 10; // no-warning
43+
array[5 &idx] = 12; // no-warning
44+
array[idx & 11 & 5] = 3; // no warning
45+
array[idx & 11] = 20; // expected-note{{used in buffer access here}}
46+
array[idx &=5]; // expected-note{{used in buffer access here}}
47+
array[f.x & 5]; // no-warning
48+
array[5 & f.x]; // no-warning
49+
array[f.x & (-5)]; // expected-note{{used in buffer access here}}
50+
}
51+
52+
typedef unsigned long long uint64_t;
53+
typedef unsigned int uint32_t;
54+
typedef unsigned char uint8_t;
55+
56+
void type_conversions(uint64_t idx1, uint32_t idx2, uint8_t idx3) {
57+
array[(uint32_t)idx1 & 3];
58+
array[idx2 & 3];
59+
array[idx3 & 3];
60+
}
61+
62+
int array2[5]; // expected-warning {{'array2' is an unsafe buffer that does not perform bounds checks}}
63+
64+
void masked_idx_safe(unsigned long long idx) {
65+
array2[6 & 5]; // no warning
66+
array2[6 & idx & (idx + 1) & 5]; // expected-note{{used in buffer access here}}
67+
}
68+
3669
void constant_idx_unsafe(unsigned idx) {
3770
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
3871
// expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}}

0 commit comments

Comments
 (0)