https://github.com/malavikasamak created https://github.com/llvm/llvm-project/pull/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) >From b557d1d8c323116a4ffcf5c9cec06bb4fb133f92 Mon Sep 17 00:00:00 2001 From: MalavikaSamak <malavi...@apple.com> Date: Fri, 11 Oct 2024 12:24:58 -0700 Subject: [PATCH] [Wunsafe-buffer-usage] False positives for & expression indexing constant size array (arr[anything & 0]) (rdar://136684050) --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 45 +++++++++++++++++++ .../warn-unsafe-buffer-usage-array.cpp | 14 ++++++ 2 files changed, 59 insertions(+) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 97f1c4f16b8f4c..cdfdcc17536391 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -427,6 +427,45 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { // - e. g. "Try harder to find a NamedDecl to point at in the note." // already duplicated // - call both from Sema and from here + std::function<bool(const Expr *exp, const ConstantArrayType *CATy, + unsigned int limit)> + SafeMaskedAccess; + unsigned int RecLimit = 5; + llvm::APInt Max; + bool Initialized = false; + + SafeMaskedAccess = [&](const Expr *exp, const ConstantArrayType *CATy, + unsigned int RecLimit) -> bool { + if (RecLimit == 0) + return false; + + RecLimit--; + + if (const auto *IntLit = dyn_cast<IntegerLiteral>(exp)) { + const APInt ArrIdx = IntLit->getValue(); + if (ArrIdx.isNonNegative() && + ArrIdx.getLimitedValue() < CATy->getLimitedSize()) + return true; + if (!Initialized) { + Max = ArrIdx; + Initialized = true; + } else { + Max = Max & ArrIdx.getLimitedValue(); + } + if (Max.getLimitedValue() < CATy->getLimitedSize()) + return true; + } + + if (const auto *BinEx = dyn_cast<BinaryOperator>(exp)) { + if (SafeMaskedAccess(BinEx->getLHS()->IgnoreParenCasts(), CATy, RecLimit)) + return true; + else if (SafeMaskedAccess(BinEx->getRHS()->IgnoreParenCasts(), CATy, + RecLimit)) + return true; + } + + return false; + }; const auto *BaseDRE = dyn_cast<DeclRefExpr>(Node.getBase()->IgnoreParenImpCasts()); @@ -446,6 +485,12 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < CATy->getLimitedSize()) return true; + } else if (const auto *BinEx = dyn_cast<BinaryOperator>(Node.getIdx())) { + if (BinEx->getOpcode() != BO_And) + return false; + + Max.setAllBits(); + return SafeMaskedAccess(Node.getIdx(), CATy, RecLimit); } return false; diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index 8b2f103ec66708..e5a5ca57f66883 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -33,6 +33,20 @@ void constant_idx_safe0(unsigned idx) { buffer[0] = 0; } +int array[10]; // expected-warning{{'array' is an unsafe buffer that does not perform bounds checks}} + +void masked_idx(unsigned long long idx) { + array[idx & 5] = 10; // no warning + array[idx & 11 & 5] = 3; // no warning + array[idx & 11] = 20; // expected-note{{used in buffer access here}} +} + +int array2[5]; + +void mased_idx_false() { + array2[6 & 5]; +} + void constant_idx_unsafe(unsigned idx) { int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}} // expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits