[PATCH] D158156: [analyzer] Add C++ array delete checker

Balázs Benics via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 11 05:06:05 PDT 2023


steakhal added a comment.

I have concerns mostly about the cast visitor.



================
Comment at: clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp:192
+
+  const Stmt *S = N->getStmtForDiagnostics();
+  if (!S)
----------------
Discookie wrote:
> steakhal wrote:
> > Aren't you actually interested in N->getLocation().getAs<StmtPoint>().getStmt()?
> > 
> > The diag stmt can be fuzzy, but the PP is exact.
> As far as I can tell, getStmtForDiagnostics() does exactly that, but with a bit more edge case handling and a couple fallbacks.
If they do the same, and it does not depend on the mentioned fallbacks, I think we should use the Stmt of the programpoint to be explicit.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp:194-201
   // Only interested in DerivedToBase implicit casts.
   // Explicit casts can have different CastKinds.
+  // FIXME: The checker currently matches all explicit casts,
+  // but only ones casting to a base class (or simular) should be matcherd.
   if (const auto *ImplCastE = dyn_cast<ImplicitCastExpr>(CastE)) {
     if (ImplCastE->getCastKind() != CK_DerivedToBase)
       return nullptr;
----------------
Have you considered `dyn_cast<CastExpr>()` to make it work for both implicit and explicit casts?
BTW `simular` -> `similar`


================
Comment at: clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp:220
                              N->getLocationContext());
-  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
+  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), /*addPosRange=*/true);
+}
----------------
We should assert that this visitor always adds a Note. In other words, that it must find the Stmt where the derived->base conversion happened. If ever that's not true, we have a bug.


================
Comment at: clang/test/Analysis/ArrayDelete.cpp:85-88
+    Derived *d3 = new DoubleDerived[10];
+    Base *b3 = d3; // expected-note{{Conversion from derived to base happened here}}
+    delete[] b3; // expected-warning{{Deleting an array of polymorphic objects is undefined}}
+    // expected-note at -1{{Deleting an array of polymorphic objects is undefined}}
----------------
Hmm, the static type of `d3` doesn't tell us much about how it refers to an object of type `DoubleDerived`.
To me, it would make sense to have multiple `Conversion from derived to base happened here`, even telling us what static type it converted to what other static type in the message.
And it should add a new visitor of the same kind tracking the castee.

```
Derived *d3 = new DoubleDerived[10]; // note: `DoubleDerived` -> `Derived` here
Base *b3 = d3; // note: `Derived` -> `Base` here
delete[] b3; // warn: Deleting `Derived` objects as `Base` objects.
```
WDYT @donat.nagy ?


================
Comment at: clang/test/Analysis/ArrayDelete.cpp:90-93
+    Base *b4 = new DoubleDerived[10];
+    Derived *d4 = reinterpret_cast<Derived*>(b4);
+    DoubleDerived *dd4 = reinterpret_cast<DoubleDerived*>(d4);
+    delete[] dd4; // no-warning
----------------
I think in such cases a `static_cast` should suffice; unless you intentionally wanted to test `reinterpret_cast` of course.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158156/new/

https://reviews.llvm.org/D158156



More information about the cfe-commits mailing list