Skip to content

Commit b557d1d

Browse files
author
MalavikaSamak
committed
[Wunsafe-buffer-usage] False positives for & expression indexing constant size array (arr[anything & 0])
(rdar://136684050)
1 parent 2ff4c25 commit b557d1d

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,45 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
427427
// - e. g. "Try harder to find a NamedDecl to point at in the note."
428428
// already duplicated
429429
// - call both from Sema and from here
430+
std::function<bool(const Expr *exp, const ConstantArrayType *CATy,
431+
unsigned int limit)>
432+
SafeMaskedAccess;
433+
unsigned int RecLimit = 5;
434+
llvm::APInt Max;
435+
bool Initialized = false;
436+
437+
SafeMaskedAccess = [&](const Expr *exp, const ConstantArrayType *CATy,
438+
unsigned int RecLimit) -> bool {
439+
if (RecLimit == 0)
440+
return false;
441+
442+
RecLimit--;
443+
444+
if (const auto *IntLit = dyn_cast<IntegerLiteral>(exp)) {
445+
const APInt ArrIdx = IntLit->getValue();
446+
if (ArrIdx.isNonNegative() &&
447+
ArrIdx.getLimitedValue() < CATy->getLimitedSize())
448+
return true;
449+
if (!Initialized) {
450+
Max = ArrIdx;
451+
Initialized = true;
452+
} else {
453+
Max = Max & ArrIdx.getLimitedValue();
454+
}
455+
if (Max.getLimitedValue() < CATy->getLimitedSize())
456+
return true;
457+
}
458+
459+
if (const auto *BinEx = dyn_cast<BinaryOperator>(exp)) {
460+
if (SafeMaskedAccess(BinEx->getLHS()->IgnoreParenCasts(), CATy, RecLimit))
461+
return true;
462+
else if (SafeMaskedAccess(BinEx->getRHS()->IgnoreParenCasts(), CATy,
463+
RecLimit))
464+
return true;
465+
}
466+
467+
return false;
468+
};
430469

431470
const auto *BaseDRE =
432471
dyn_cast<DeclRefExpr>(Node.getBase()->IgnoreParenImpCasts());
@@ -446,6 +485,12 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
446485
if (ArrIdx.isNonNegative() &&
447486
ArrIdx.getLimitedValue() < CATy->getLimitedSize())
448487
return true;
488+
} else if (const auto *BinEx = dyn_cast<BinaryOperator>(Node.getIdx())) {
489+
if (BinEx->getOpcode() != BO_And)
490+
return false;
491+
492+
Max.setAllBits();
493+
return SafeMaskedAccess(Node.getIdx(), CATy, RecLimit);
449494
}
450495

451496
return false;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ void constant_idx_safe0(unsigned idx) {
3333
buffer[0] = 0;
3434
}
3535

36+
int array[10]; // expected-warning{{'array' is an unsafe buffer that does not perform bounds checks}}
37+
38+
void masked_idx(unsigned long long idx) {
39+
array[idx & 5] = 10; // no warning
40+
array[idx & 11 & 5] = 3; // no warning
41+
array[idx & 11] = 20; // expected-note{{used in buffer access here}}
42+
}
43+
44+
int array2[5];
45+
46+
void mased_idx_false() {
47+
array2[6 & 5];
48+
}
49+
3650
void constant_idx_unsafe(unsigned idx) {
3751
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
3852
// expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}}

0 commit comments

Comments
 (0)