Skip to content

Commit 5dc8ea8

Browse files
Merge pull request #10105 from swiftlang/msamak-cherry-pick-const-bit-and
[Cherry-pick] [Wunsafe-buffer-usage] False positives for & expression indexing constant size array (arr[anything & 0]) (llvm#112284)
2 parents b63edb6 + 8b75f06 commit 5dc8ea8

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
@@ -1053,6 +1053,25 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
10531053
// bug
10541054
if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
10551055
return true;
1056+
} else if (const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
1057+
// For an integer expression `e` and an integer constant `n`, `e & n` and
1058+
// `n & e` are bounded by `n`:
1059+
if (BE->getOpcode() != BO_And)
1060+
return false;
1061+
1062+
const Expr *LHS = BE->getLHS();
1063+
const Expr *RHS = BE->getRHS();
1064+
1065+
if ((!LHS->isValueDependent() &&
1066+
LHS->EvaluateAsInt(EVResult,
1067+
Finder->getASTContext())) || // case: `n & e`
1068+
(!RHS->isValueDependent() &&
1069+
RHS->EvaluateAsInt(EVResult, Finder->getASTContext()))) { // `e & n`
1070+
llvm::APSInt result = EVResult.Val.getInt();
1071+
if (result.isNonNegative() && result.getLimitedValue() < limit)
1072+
return true;
1073+
}
1074+
return false;
10561075
}
10571076
return false;
10581077
}

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)