Skip to content

Commit bf1f0b8

Browse files
author
MalavikaSamak
committed
[Wunsafe-buffer-usage] False positives for & expression indexing constant size array (arr[anything & 0])
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
1 parent 76e73ae commit bf1f0b8

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

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

469486
AST_MATCHER_P(CallExpr, hasNumArgs, unsigned, Num) {

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

Lines changed: 31 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,35 @@ 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[idx & 11 & 5] = 3; // no warning
44+
array[idx & 11] = 20; // expected-note{{used in buffer access here}}
45+
array[idx &=5]; // expected-note{{used in buffer access here}}
46+
array[f.x & 5];
47+
}
48+
49+
typedef unsigned long long uint64_t;
50+
typedef unsigned int uint32_t;
51+
typedef unsigned char uint8_t;
52+
53+
void type_conversions(uint64_t idx1, uint32_t idx2, uint8_t idx3) {
54+
array[(uint32_t)idx1 & 3];
55+
array[idx2 & 3];
56+
array[idx3 & 3];
57+
}
58+
59+
int array2[5]; // expected-warning {{'array2' is an unsafe buffer that does not perform bounds checks}}
60+
61+
void masked_idx_safe(unsigned long long idx) {
62+
array2[6 & 5]; // no warning
63+
array2[6 & idx & (idx + 1) & 5]; // expected-note{{used in buffer access here}}
64+
}
65+
66+
3667
void constant_idx_unsafe(unsigned idx) {
3768
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
3869
// expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}}

0 commit comments

Comments
 (0)