[clang] [clang][analyzer] Improve 'errno' handling in StdLibraryFunctionsChecker. (PR #71392)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 7 08:25:44 PST 2023


================
@@ -1418,31 +1423,42 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
               return "";
             });
         Pred = C.addTransition(NewState, Pred, Tag);
-      } else {
-        const NoteTag *Tag =
-            C.getNoteTag([Note, RV](PathSensitiveBugReport &BR) -> std::string {
-              if (BR.isInteresting(RV))
-                return Note;
+      }
+    } else {
+      if (!Note.empty() || !ErrnoNote.empty()) {
+        const NoteTag *Tag = C.getNoteTag(
+            [Note, ErrnoNote, RV](PathSensitiveBugReport &BR) -> std::string {
+              // If 'errno' is interesting, show the user a note about the case
+              // (what happened at the function call) and about how 'errno'
+              // causes the problem. ErrnoChecker sets the errno (but not RV) to
+              // interesting.
+              // If only the return value is interesting, show only the case
+              // note.
+              std::optional<Loc> ErrnoLoc =
+                  errno_modeling::getErrnoLoc(BR.getErrorNode()->getState());
+              bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
+                                    BR.isInteresting(ErrnoLoc->getAsRegion());
+              if (ErrnoImportant) {
+                BR.markNotInteresting(ErrnoLoc->getAsRegion());
+                if (Note.empty())
+                  return ErrnoNote;
+                return llvm::formatv("{0}; {1}", Note, ErrnoNote);
+              } else {
+                if (BR.isInteresting(RV))
+                  return Note;
+              }
               return "";
             });
         Pred = C.addTransition(NewState, Pred, Tag);
       }
-
-      // Pred may be:
-      //  - a nullpointer, if we reach an already existing node (theoretically);
-      //  - a sink, when NewState is posteriorly overconstrained.
-      // In these situations we cannot add the errno note tag.
-      if (!Pred || Pred->isSink())
-        continue;
     }
 
-    // If we can get a note tag for the errno change, add this additionally to
-    // the previous. This note is only about value of 'errno' and is displayed
-    // if 'errno' is interesting.
-    if (const auto *D = dyn_cast<FunctionDecl>(Call.getDecl()))
-      if (const NoteTag *NT =
-              Case.getErrnoConstraint().describe(C, D->getNameAsString()))
-        Pred = C.addTransition(NewState, Pred, NT);
+    // Pred may be:
+    //  - a nullpointer, if we reach an already existing node (theoretically);
+    //  - a sink, when NewState is posteriorly overconstrained.
+    // In these situations we cannot add the errno note tag.
+    if (!Pred || Pred->isSink())
+      continue;
----------------
DonatNagyE wrote:

```suggestion
```
This check can be removed; it was only needed to satisfy the preconditions of the `C.addTransition(NewState, Pred, NT);` call when the code applied the note tag for the errno change as a second separate transition starting in `Pred`.

The next if only operates in the trivial case when `Pred` still holds the unchanged initial `Node` (which is clearly non-null and AFAIK non-sink) and it also doesn't try to build an explicit transition onto `Pred`. (Note that `Pred` is declared in the middle of the loop, it doesn't survive into the next iteration.)

For the sake of ~~paranoia~~ safety, test the behavior of the code on some open source projects, but I don't see any reasons how this could introduce issues.

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


More information about the cfe-commits mailing list