[clang] [Safe Buffers] Fix a small bug recently found (PR #102953)

Ziqing Luo via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 13 15:07:36 PDT 2024


https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/102953

>From d6c860de3facc37f27b17a26a01e48bc02b4659b Mon Sep 17 00:00:00 2001
From: ziqingluo-90 <ziqing_luo at apple.com>
Date: Mon, 12 Aug 2024 11:57:17 -0700
Subject: [PATCH] [-Wunsafe-buffer-usage] Fix a bug in the ASTMatcher for span
 constructors

`QualType::isConstantArrayType()` checks canonical type. So a
following cast should be applied to canonical type as well. And, a
better option is to use `ASTContext::getAsArrayType()`.

```
if (Ty->isConstantArrayType())
  cast<ConstantArrayType>(Ty); // this is incorrect

if (auto *CAT = Context.getAsConstantArrayType(Ty))
  ...                          // this is good

```
---
 clang/lib/Analysis/UnsafeBufferUsage.cpp           | 14 +++++++-------
 ...fe-buffer-usage-in-container-span-construct.cpp |  3 +++
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 866222380974b6..db7ec5741f91c4 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -402,9 +402,9 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
 
   QualType Arg0Ty = Arg0->IgnoreImplicit()->getType();
 
-  if (Arg0Ty->isConstantArrayType()) {
-    const APSInt ConstArrSize =
-        APSInt(cast<ConstantArrayType>(Arg0Ty)->getSize());
+  if (auto *ConstArrTy =
+          Finder->getASTContext().getAsConstantArrayType(Arg0Ty)) {
+    const APSInt ConstArrSize = APSInt(ConstArrTy->getSize());
 
     // Check form 4:
     return Arg1CV && APSInt::compareValues(ConstArrSize, *Arg1CV) == 0;
@@ -2659,7 +2659,7 @@ static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx,
 
   // Note: the code below expects the declaration to not use any type sugar like
   // typedef.
-  if (auto CAT = dyn_cast<clang::ConstantArrayType>(D->getType())) {
+  if (auto CAT = Ctx.getAsConstantArrayType(D->getType())) {
     const QualType &ArrayEltT = CAT->getElementType();
     assert(!ArrayEltT.isNull() && "Trying to fix a non-array type variable!");
     // FIXME: support multi-dimensional arrays
@@ -2792,9 +2792,9 @@ fixVariable(const VarDecl *VD, FixitStrategy::Kind K,
     return {};
   }
   case FixitStrategy::Kind::Array: {
-    if (VD->isLocalVarDecl() &&
-        isa<clang::ConstantArrayType>(VD->getType().getCanonicalType()))
-      return fixVariableWithArray(VD, Tracker, Ctx, Handler);
+    if (VD->isLocalVarDecl())
+      if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+        return fixVariableWithArray(VD, Tracker, Ctx, Handler);
 
     DEBUG_NOTE_DECL_FAIL(VD, " : not a local const-size array");
     return {};
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp
index a1ddc384e0d9b8..e97511593bbd81 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp
@@ -79,6 +79,8 @@ namespace construct_wt_ptr_size {
     unsigned Y = 10;
     std::span<int> S = std::span{&X, 1}; // no-warning
     int Arr[10];
+    typedef int TenInts_t[10];
+    TenInts_t Arr2;
 
     S = std::span{&X, 2};                // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
     S = std::span{new int[10], 10};      // no-warning
@@ -90,6 +92,7 @@ namespace construct_wt_ptr_size {
     S = std::span{new int[10], 9};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
     S = std::span{new int[10], Y};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
     S = std::span{Arr, 10};              // no-warning
+    S = std::span{Arr2, 10};             // no-warning
     S = std::span{Arr, Y};               // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
     S = std::span{p, 0};                 // no-warning
   }



More information about the cfe-commits mailing list