Skip to content

Commit 9e5964f

Browse files
committed
[-Wunsafe-buffer-usage] Ignore safe array subscripts
Don't emit warnings for array subscripts on constant size arrays where the index is constant and within bounds. Example: int arr[10]; arr[5] = 0; //safe, no warning This patch recognizes only array indices that are integer literals - it doesn't understand more complex expressions (arithmetic on constants, etc.).
1 parent 76a91cf commit 9e5964f

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
406406
}
407407
return false;
408408
}
409+
410+
AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
411+
const DeclRefExpr * BaseDRE = dyn_cast_or_null<DeclRefExpr>(Node.getBase()->IgnoreParenImpCasts());
412+
if (!BaseDRE)
413+
return false;
414+
if (!BaseDRE->getDecl())
415+
return false;
416+
auto BaseVarDeclTy = BaseDRE->getDecl()->getType();
417+
if (!BaseVarDeclTy->isConstantArrayType())
418+
return false;
419+
const auto * CATy = dyn_cast_or_null<ConstantArrayType>(BaseVarDeclTy);
420+
if (!CATy)
421+
return false;
422+
const APInt ArrSize = CATy->getSize();
423+
424+
if (const auto * IdxLit = dyn_cast<IntegerLiteral>(Node.getIdx())) {
425+
const APInt ArrIdx = IdxLit->getValue();
426+
// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a bug
427+
if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < ArrSize.getLimitedValue())
428+
return true;
429+
}
430+
431+
return false;
432+
}
433+
409434
} // namespace clang::ast_matchers
410435

411436
namespace {
@@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget {
598623
}
599624

600625
static Matcher matcher() {
601-
// FIXME: What if the index is integer literal 0? Should this be
602-
// a safe gadget in this case?
603-
// clang-format off
626+
// clang-format off
604627
return stmt(arraySubscriptExpr(
605628
hasBase(ignoringParenImpCasts(
606629
anyOf(hasPointerType(), hasArrayType()))),
607-
unless(hasIndex(
608-
anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
609-
)))
610-
.bind(ArraySubscrTag));
630+
unless(anyOf(
631+
isSafeArraySubscript(),
632+
hasIndex(
633+
anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
634+
)
635+
))).bind(ArraySubscrTag));
611636
// clang-format on
612637
}
613638

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \
1+
// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \
22
// RUN: -fsafe-buffer-usage-suggestions \
33
// RUN: -verify %s
44

@@ -22,3 +22,19 @@ struct Foo {
2222
void foo2(Foo& f, unsigned idx) {
2323
f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}}
2424
}
25+
26+
void constant_idx_safe(unsigned idx) {
27+
int buffer[10];
28+
buffer[9] = 0;
29+
}
30+
31+
void constant_idx_safe0(unsigned idx) {
32+
int buffer[10];
33+
buffer[0] = 0;
34+
}
35+
36+
void constant_idx_unsafe(unsigned idx) {
37+
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
38+
// expected-note@-1{{change type of 'buffer' to 'std::array' to harden it}}
39+
buffer[10] = 0; // expected-note{{used in buffer access here}}
40+
}

0 commit comments

Comments
 (0)