[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

Balázs Benics via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 25 04:54:07 PDT 2021


steakhal added a comment.

In D97183#2640559 <https://reviews.llvm.org/D97183#2640559>, @RedDocMD wrote:

> @NoQ, why does the following trigger a null-dereference warning? (https://godbolt.org/z/Kxox8qd16)
>
>   void g(std::unique_ptr<A> a) {
>     A *aptr = a.get();
>     if (!aptr) {}
>     a->foo();
>   }
>
> When `a->foo()` is called, the constraint `!aptr` is no longer valid and so `InnerPointerVal` corresponding to `a` is no longer constrained to be null.
> Am I missing something?

When the if's condition is evaluated, it probably triggered a state split. On one path the `aptr` (aka. the inner pointer) will be constrained to `null`.
The only way to be sure is by checking the exploded graph and see where it goes.

---

In D97183#2643671 <https://reviews.llvm.org/D97183#2643671>, @RedDocMD wrote:

> @NoQ, I have taken a different approach this time. I have used a visitor and am storing some more data in the GDM. Together, they distinguish between the following three cases:
>
> 1. If the raw pointer obtained from get() is constrained to null in a path which leads to a Node (and thus State) where a smart-pointer-null-deref bug occurs.
> 2. If the raw pointer was null to begin with (because the smart-pointer was null)
> 3. If the raw pointer was not null to begin with but the smart-ptr became null after that.
>
> Only in the first case should the note be emitted. I have added some more tests to that effect.

All in all, I see where it's going. I don't know, it might be the right thing to do. I haven't spent much time on this topic though.
See my inline comments.



================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:87
+  const ProgramStateRef BugState;
+  llvm::SmallPtrSet<const Expr *, 16> DoneExprs;
+
----------------
I'm not sure if we should expect 16 unique places where `uptr::get()` called on a path. I would guess 4 or 2 is more than enough.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:106-109
+    if (const auto *DS = llvm::dyn_cast<DeclStmt>(S)) {
+      for (const Decl *D : DS->getDeclGroup()) {
+        if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
+          const Expr *Init = VD->getInit();
----------------
So you are trying to find the assignment, where the inner pointer is assigned to a variable.
This visitor logic seems to be somewhat convoluted.

What you want to achieve is slightly similar to `FindLastStoreBRVisitor`. You should have a look at that.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:460
   SVal InnerPointerVal;
+  const auto *CallExpr = Call.getOriginExpr();
   if (const auto *InnerValPtr = State->get<TrackedRegionMap>(ThisRegion)) {
----------------
Nit: Declare the variable as close to the usage as you can. In the narrowest scope as well.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:475-476
+  if (const auto *StmtSet = State->get<ExprsFromGet>(ThisRegion)) {
+    auto NewStmtSet = StmtSetFactory.add(*StmtSet, CallExpr);
+    State = State->set<ExprsFromGet>(ThisRegion, NewStmtSet);
+  } else {
----------------
Why don't you 'save' the MemRegion only if the inner pointer is not proven to be null. This would relieve you from checking it later.

Nit: I don't like such if branches. The last statement is identical, which is a code smell.
It's better to think of this as a function taking stuff and producing a State.
An immediately called lambda expression would enclose any local variables and it would suggest that the algorithm it implements is self-contained.
I know that I'm the only immediately called lambda expression fan though.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183



More information about the cfe-commits mailing list