[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 28 06:55:31 PST 2025


================
@@ -1986,112 +2360,119 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
   }
 };
 
-/// Scan the function and return a list of gadgets found with provided kits.
-static void findGadgets(const Stmt *S, ASTContext &Ctx,
-                        const UnsafeBufferUsageHandler &Handler,
-                        bool EmitSuggestions, FixableGadgetList &FixableGadgets,
-                        WarningGadgetList &WarningGadgets,
-                        DeclUseTracker &Tracker) {
+class EvaluatedStmtMatcher : public FastMatcher {
 
-  struct GadgetFinderCallback : MatchFinder::MatchCallback {
-    GadgetFinderCallback(FixableGadgetList &FixableGadgets,
-                         WarningGadgetList &WarningGadgets,
-                         DeclUseTracker &Tracker)
-        : FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
-          Tracker(Tracker) {}
-
-    void run(const MatchFinder::MatchResult &Result) override {
-      // In debug mode, assert that we've found exactly one gadget.
-      // This helps us avoid conflicts in .bind() tags.
-#if NDEBUG
-#define NEXT return
-#else
-      [[maybe_unused]] int numFound = 0;
-#define NEXT ++numFound
-#endif
-
-      if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("any_dre")) {
-        Tracker.discoverUse(DRE);
-        NEXT;
-      }
+public:
+  EvaluatedStmtMatcher(WarningGadgetList &WarningGadgets)
+      : WarningGadgets(WarningGadgets) {}
 
-      if (const auto *DS = Result.Nodes.getNodeAs<DeclStmt>("any_ds")) {
-        Tracker.discoverDecl(DS);
-        NEXT;
-      }
+  bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
+               const UnsafeBufferUsageHandler &Handler) override {
+    const Stmt *S = DynNode.get<Stmt>();
+    if (!S)
+      return false;
 
-      // Figure out which matcher we've found, and call the appropriate
-      // subclass constructor.
-      // FIXME: Can we do this more logarithmically?
-#define FIXABLE_GADGET(name)                                                   \
-  if (Result.Nodes.getNodeAs<Stmt>(#name)) {                                   \
-    FixableGadgets.push_back(std::make_unique<name##Gadget>(Result));          \
-    NEXT;                                                                      \
-  }
-#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+    MatchResult Result;
 #define WARNING_GADGET(name)                                                   \
-  if (Result.Nodes.getNodeAs<Stmt>(#name)) {                                   \
+  if (name##Gadget::matches(S, Ctx, Result) &&                                 \
+      notInSafeBufferOptOut(*S, &Handler)) {                                   \
+    WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));          \
+    return true;                                                               \
+  }
+#define WARNING_OPTIONAL_GADGET(name)                                          \
+  if (name##Gadget::matches(S, Ctx, &Handler, Result) &&                       \
+      notInSafeBufferOptOut(*S, &Handler)) {                                   \
     WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));          \
-    NEXT;                                                                      \
+    return true;                                                               \
   }
 #include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+    return false;
+  }
 
-      assert(numFound >= 1 && "Gadgets not found in match result!");
-      assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
-    }
+private:
+  WarningGadgetList &WarningGadgets;
+};
 
-    FixableGadgetList &FixableGadgets;
-    WarningGadgetList &WarningGadgets;
-    DeclUseTracker &Tracker;
-  };
+class StmtMatcher : public FastMatcher {
 
-  MatchFinder M;
-  GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
-
-  // clang-format off
-  M.addMatcher(
-      stmt(
-        forEachDescendantEvaluatedStmt(stmt(anyOf(
-          // Add Gadget::matcher() for every gadget in the registry.
-#define WARNING_GADGET(x)                                                      \
-          allOf(x ## Gadget::matcher().bind(#x),                               \
-                notInSafeBufferOptOut(&Handler)),
-#define WARNING_OPTIONAL_GADGET(x)                                            \
-          allOf(x ## Gadget::matcher(&Handler).bind(#x),                      \
-                notInSafeBufferOptOut(&Handler)),
-#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
-            // Avoid a hanging comma.
-            unless(stmt())
-        )))
-    ),
-    &CB
-  );
-  // clang-format on
+public:
+  StmtMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
+      : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
+
+  // Match all DeclRefExprs so that to find out
+  // whether there are any uncovered by gadgets.
+  bool matchDeclRefExprs(const Stmt *S, MatchResult &Result) {
----------------
ilya-biryukov wrote:

NIT: Using `MatchResult` here seems completely unnecessary. Could we instead do this?

```cpp
DeclRefExpr* findDeclRefExpr(const Stmt *S) {
      const auto *DRE = dyn_cast<DeclRefExpr>(S);
    if (!DRE || (!hasPointerType(*DRE) && !hasArrayType(*DRE)))
      return nullptr;
    const Decl *D = DRE->getDecl();
    if (!D || (!isa<VarDecl>(D) && !isa<BindingDecl>(D)))
      return nullptr;
    return DRE;
}
```

The call site will be simplified and this function is simplified too.
Same for `matchDeclStmt`

https://github.com/llvm/llvm-project/pull/125492


More information about the cfe-commits mailing list