r370798 - [analyzer] NonNullParamChecker and CStringChecker parameter number in checker message

Kristof Umann via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 3 10:57:01 PDT 2019


Author: szelethus
Date: Tue Sep  3 10:57:01 2019
New Revision: 370798

URL: http://llvm.org/viewvc/llvm-project?rev=370798&view=rev
Log:
[analyzer] NonNullParamChecker and CStringChecker parameter number in checker message

There are some functions which can't be given a null pointer as parameter either
because it has a nonnull attribute or it is declared to have undefined behavior
(e.g. strcmp()). Sometimes it is hard to determine from the checker message
which parameter is null at the invocation, so now this information is included
in the message.

This commit fixes https://bugs.llvm.org/show_bug.cgi?id=39358

Reviewed By: NoQ, Szelethus, whisperity

Patch by Tibor Brunner!

Differential Revision: https://reviews.llvm.org/D66333

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
    cfe/trunk/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
    cfe/trunk/test/Analysis/Inputs/expected-plists/plist-output.m.plist
    cfe/trunk/test/Analysis/misc-ps-region-store.m
    cfe/trunk/test/Analysis/null-deref-ps.c

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Tue Sep  3 10:57:01 2019
@@ -198,7 +198,8 @@ public:
   ProgramStateRef checkNonNull(CheckerContext &C,
                                    ProgramStateRef state,
                                    const Expr *S,
-                                   SVal l) const;
+                                   SVal l,
+                                   unsigned IdxOfArg) const;
   ProgramStateRef CheckLocation(CheckerContext &C,
                                     ProgramStateRef state,
                                     const Expr *S,
@@ -277,7 +278,8 @@ CStringChecker::assumeZero(CheckerContex
 
 ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
                                             ProgramStateRef state,
-                                            const Expr *S, SVal l) const {
+                                            const Expr *S, SVal l,
+                                            unsigned IdxOfArg) const {
   // If a previous check has failed, propagate the failure.
   if (!state)
     return nullptr;
@@ -288,11 +290,13 @@ ProgramStateRef CStringChecker::checkNon
   if (stateNull && !stateNonNull) {
     if (Filter.CheckCStringNullArg) {
       SmallString<80> buf;
-      llvm::raw_svector_ostream os(buf);
+      llvm::raw_svector_ostream OS(buf);
       assert(CurrentFunctionDescription);
-      os << "Null pointer argument in call to " << CurrentFunctionDescription;
+      OS << "Null pointer argument in call to " << CurrentFunctionDescription
+         << ' ' << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
+         << " parameter";
 
-      emitNullArgBug(C, stateNull, S, os.str());
+      emitNullArgBug(C, stateNull, S, OS.str());
     }
     return nullptr;
   }
@@ -384,7 +388,7 @@ ProgramStateRef CStringChecker::CheckBuf
 
   // Check that the first buffer is non-null.
   SVal BufVal = C.getSVal(FirstBuf);
-  state = checkNonNull(C, state, FirstBuf, BufVal);
+  state = checkNonNull(C, state, FirstBuf, BufVal, 1);
   if (!state)
     return nullptr;
 
@@ -424,7 +428,7 @@ ProgramStateRef CStringChecker::CheckBuf
   // If there's a second buffer, check it as well.
   if (SecondBuf) {
     BufVal = state->getSVal(SecondBuf, LCtx);
-    state = checkNonNull(C, state, SecondBuf, BufVal);
+    state = checkNonNull(C, state, SecondBuf, BufVal, 2);
     if (!state)
       return nullptr;
 
@@ -1163,7 +1167,7 @@ void CStringChecker::evalCopyCommon(Chec
 
     // Ensure the destination is not null. If it is NULL there will be a
     // NULL pointer dereference.
-    state = checkNonNull(C, state, Dest, destVal);
+    state = checkNonNull(C, state, Dest, destVal, 1);
     if (!state)
       return;
 
@@ -1172,7 +1176,7 @@ void CStringChecker::evalCopyCommon(Chec
 
     // Ensure the source is not null. If it is NULL there will be a
     // NULL pointer dereference.
-    state = checkNonNull(C, state, Source, srcVal);
+    state = checkNonNull(C, state, Source, srcVal, 2);
     if (!state)
       return;
 
@@ -1383,7 +1387,7 @@ void CStringChecker::evalstrLengthCommon
   const Expr *Arg = CE->getArg(0);
   SVal ArgVal = state->getSVal(Arg, LCtx);
 
-  state = checkNonNull(C, state, Arg, ArgVal);
+  state = checkNonNull(C, state, Arg, ArgVal, 1);
 
   if (!state)
     return;
@@ -1541,14 +1545,14 @@ void CStringChecker::evalStrcpyCommon(Ch
   const Expr *Dst = CE->getArg(0);
   SVal DstVal = state->getSVal(Dst, LCtx);
 
-  state = checkNonNull(C, state, Dst, DstVal);
+  state = checkNonNull(C, state, Dst, DstVal, 1);
   if (!state)
     return;
 
   // Check that the source is non-null.
   const Expr *srcExpr = CE->getArg(1);
   SVal srcVal = state->getSVal(srcExpr, LCtx);
-  state = checkNonNull(C, state, srcExpr, srcVal);
+  state = checkNonNull(C, state, srcExpr, srcVal, 2);
   if (!state)
     return;
 
@@ -1904,14 +1908,14 @@ void CStringChecker::evalStrcmpCommon(Ch
   // Check that the first string is non-null
   const Expr *s1 = CE->getArg(0);
   SVal s1Val = state->getSVal(s1, LCtx);
-  state = checkNonNull(C, state, s1, s1Val);
+  state = checkNonNull(C, state, s1, s1Val, 1);
   if (!state)
     return;
 
   // Check that the second string is non-null.
   const Expr *s2 = CE->getArg(1);
   SVal s2Val = state->getSVal(s2, LCtx);
-  state = checkNonNull(C, state, s2, s2Val);
+  state = checkNonNull(C, state, s2, s2Val, 2);
   if (!state)
     return;
 
@@ -2038,14 +2042,14 @@ void CStringChecker::evalStrsep(CheckerC
   // Check that the search string pointer is non-null (though it may point to
   // a null string).
   SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx);
-  State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
+  State = checkNonNull(C, State, SearchStrPtr, SearchStrVal, 1);
   if (!State)
     return;
 
   // Check that the delimiter string is non-null.
   const Expr *DelimStr = CE->getArg(1);
   SVal DelimStrVal = State->getSVal(DelimStr, LCtx);
-  State = checkNonNull(C, State, DelimStr, DelimStrVal);
+  State = checkNonNull(C, State, DelimStr, DelimStrVal, 2);
   if (!State)
     return;
 
@@ -2148,7 +2152,7 @@ void CStringChecker::evalMemset(CheckerC
 
   // Ensure the memory area is not null.
   // If it is NULL there will be a NULL pointer dereference.
-  State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+  State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
   if (!State)
     return;
 
@@ -2195,7 +2199,7 @@ void CStringChecker::evalBzero(CheckerCo
 
   // Ensure the memory area is not null.
   // If it is NULL there will be a NULL pointer dereference.
-  State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+  State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
   if (!State)
     return;
 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp Tue Sep  3 10:57:01 2019
@@ -36,7 +36,9 @@ public:
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
 
   std::unique_ptr<BugReport>
-  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
+  genReportNullAttrNonNull(const ExplodedNode *ErrorN,
+                           const Expr *ArgE,
+                           unsigned IdxOfArg) const;
   std::unique_ptr<BugReport>
   genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
                                   const Expr *ArgE) const;
@@ -143,7 +145,7 @@ void NonNullParamChecker::checkPreCall(c
 
         std::unique_ptr<BugReport> R;
         if (haveAttrNonNull)
-          R = genReportNullAttrNonNull(errorNode, ArgE);
+          R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
         else if (haveRefTypeParam)
           R = genReportReferenceToNullPointer(errorNode, ArgE);
 
@@ -179,7 +181,8 @@ void NonNullParamChecker::checkPreCall(c
 
 std::unique_ptr<BugReport>
 NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
-                                              const Expr *ArgE) const {
+                                              const Expr *ArgE,
+                                              unsigned IdxOfArg) const {
   // Lazily allocate the BugType object if it hasn't already been
   // created. Ownership is transferred to the BugReporter object once
   // the BugReport is passed to 'EmitWarning'.
@@ -187,9 +190,13 @@ NonNullParamChecker::genReportNullAttrNo
     BTAttrNonNull.reset(new BugType(
         this, "Argument with 'nonnull' attribute passed null", "API"));
 
-  auto R = std::make_unique<BugReport>(
-      *BTAttrNonNull,
-      "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
+  llvm::SmallString<256> SBuf;
+  llvm::raw_svector_ostream OS(SBuf);
+  OS << "Null pointer passed to "
+     << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
+     << " parameter expecting 'nonnull'";
+
+  auto R = llvm::make_unique<BugReport>(*BTAttrNonNull, SBuf, ErrorNode);
   if (ArgE)
     bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
 

Modified: cfe/trunk/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/expected-plists/edges-new.mm.plist?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/expected-plists/edges-new.mm.plist (original)
+++ cfe/trunk/test/Analysis/Inputs/expected-plists/edges-new.mm.plist Tue Sep  3 10:57:01 2019
@@ -10853,12 +10853,12 @@
      </array>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+     <string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
      <key>message</key>
-     <string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+     <string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
     </dict>
    </array>
-   <key>description</key><string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+   <key>description</key><string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
    <key>category</key><string>API</string>
    <key>type</key><string>Argument with 'nonnull' attribute passed null</string>
    <key>check_name</key><string>core.NonNullParamChecker</string>

Modified: cfe/trunk/test/Analysis/Inputs/expected-plists/plist-output.m.plist
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/expected-plists/plist-output.m.plist?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/expected-plists/plist-output.m.plist (original)
+++ cfe/trunk/test/Analysis/Inputs/expected-plists/plist-output.m.plist Tue Sep  3 10:57:01 2019
@@ -6141,12 +6141,12 @@
      </array>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+     <string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
      <key>message</key>
-     <string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+     <string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
     </dict>
    </array>
-   <key>description</key><string>Null pointer passed as an argument to a 'nonnull' parameter</string>
+   <key>description</key><string>Null pointer passed to 1st parameter expecting 'nonnull'</string>
    <key>category</key><string>API</string>
    <key>type</key><string>Argument with 'nonnull' attribute passed null</string>
    <key>check_name</key><string>core.NonNullParamChecker</string>

Modified: cfe/trunk/test/Analysis/misc-ps-region-store.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/misc-ps-region-store.m?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/misc-ps-region-store.m (original)
+++ cfe/trunk/test/Analysis/misc-ps-region-store.m Tue Sep  3 10:57:01 2019
@@ -1205,7 +1205,7 @@ void rdar_8642434_funcA(rdar_8642434_typ
 void rdar_8642434_funcB(struct rdar_8642434_typeA *x, struct rdar_8642434_typeA *y) {
   rdar_8642434_funcA(x);
   if (!y)
-    rdar_8642434_funcA(y); // expected-warning{{Null pointer passed as an argument to a 'nonnull' parameter}}
+    rdar_8642434_funcA(y); // expected-warning{{Null pointer passed to 1st parameter expecting 'nonnull'}}
 }
 
 // <rdar://problem/8848957> - Handle loads and stores from a symbolic index

Modified: cfe/trunk/test/Analysis/null-deref-ps.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/null-deref-ps.c?rev=370798&r1=370797&r2=370798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/null-deref-ps.c (original)
+++ cfe/trunk/test/Analysis/null-deref-ps.c Tue Sep  3 10:57:01 2019
@@ -88,21 +88,21 @@ int f5() {
 int bar(int* p, int q) __attribute__((nonnull));
 
 int f6(int *p) { 
-  return !p ? bar(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+  return !p ? bar(p, 1) // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
          : bar(p, 0);   // no-warning
 }
 
 int bar2(int* p, int q) __attribute__((nonnull(1)));
 
 int f6b(int *p) { 
-  return !p ? bar2(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+  return !p ? bar2(p, 1) // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
          : bar2(p, 0);   // no-warning
 }
 
 int bar3(int*p, int q, int *r) __attribute__((nonnull(1,3)));
 
 int f6c(int *p, int *q) {
-   return !p ? bar3(q, 2, p) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+   return !p ? bar3(q, 2, p) // expected-warning {{Null pointer passed to 3rd parameter expecting 'nonnull'}}
              : bar3(p, 2, q); // no-warning
 }
 




More information about the cfe-commits mailing list