Author: Balázs Kéri
Date: 2023-05-17T09:34:05+02:00
New Revision: 6012cadc400f4400c97e00da268de17e94a3f5dc

URL: 
https://github.com/llvm/llvm-project/commit/6012cadc400f4400c97e00da268de17e94a3f5dc
DIFF: 
https://github.com/llvm/llvm-project/commit/6012cadc400f4400c97e00da268de17e94a3f5dc.diff

LOG: [clang][analyzer] Display buffer sizes in StdCLibraryFunctionArgs checker

If a wrong (too small) buffer argument is found, the dynamic buffer size and
values of connected arguments are displayed in the warning message, if
these are simple known integer values.

Reviewed By: Szelethus

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

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
    clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
    clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
    clang/test/Analysis/std-c-library-functions-arg-constraints.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index ef85d60c658e..1d6f97f1b702 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -105,6 +105,11 @@ class StdLibraryFunctionsChecker
   /// Get a string representation of an argument index.
   /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
   static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
+  /// Print value X of the argument in form " (which is X)",
+  /// if the value is a fixed known value, otherwise print nothing.
+  /// This is used as simple explanation of values if possible.
+  static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
+                                const CallEvent &Call, llvm::raw_ostream &Out);
   /// Append textual description of a numeric range [RMin,RMax] to
   /// \p Out.
   static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
@@ -435,6 +440,10 @@ class StdLibraryFunctionsChecker
                   ProgramStateRef State, const Summary &Summary,
                   llvm::raw_ostream &Out) const override;
 
+    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
+                               const Summary &Summary,
+                               llvm::raw_ostream &Out) const override;
+
     std::vector<ArgNo> getArgsToTrack() const override {
       std::vector<ArgNo> Result{ArgN};
       if (SizeArgN)
@@ -870,6 +879,16 @@ void StdLibraryFunctionsChecker::printArgDesc(
   Out << " argument";
 }
 
+void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
+                                                   ProgramStateRef State,
+                                                   const CallEvent &Call,
+                                                   llvm::raw_ostream &Out) {
+  if (const llvm::APSInt *Val =
+          State->getStateManager().getSValBuilder().getKnownValue(
+              State, getArgSVal(Call, ArgN)))
+    Out << " (which is " << *Val << ")";
+}
+
 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
                                                        llvm::APSInt RMax,
                                                        QualType ArgT,
@@ -1179,13 +1198,29 @@ void 
StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
   } else if (SizeArgN) {
     Out << "the value of the ";
     printArgDesc(*SizeArgN, Out);
+    printArgValueInfo(*SizeArgN, State, Call, Out);
     if (SizeMultiplierArgN) {
       Out << " times the ";
       printArgDesc(*SizeMultiplierArgN, Out);
+      printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
     }
   }
 }
 
+bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
+    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
+    llvm::raw_ostream &Out) const {
+  SVal BufV = getArgSVal(Call, getArgNo());
+  SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
+  if (const llvm::APSInt *Val =
+          State->getStateManager().getSValBuilder().getKnownValue(State,
+                                                                  BufDynSize)) 
{
+    Out << "is a buffer with size " << *Val;
+    return true;
+  }
+  return false;
+}
+
 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
                                               CheckerContext &C) const {
   std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);

diff  --git 
a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp 
b/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
index a1b956e009f4..156b80a5488a 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
@@ -28,19 +28,19 @@ void test_buffer_size(int x) {
   case 1: {
     char buf[9];
     __buf_size_arg_constraint_concrete(buf); // \
-    // expected-warning{{The 1st argument to 
'__buf_size_arg_constraint_concrete' is out of the accepted range; It should be 
a buffer with size equal to or greater than 10 [}}
+    // expected-warning{{The 1st argument to 
'__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a 
buffer with size equal to or greater than 10 [}}
     break;
   }
   case 2: {
     char buf[3];
     __buf_size_arg_constraint(buf, 4); // \
-    // expected-warning{{The 1st argument to '__buf_size_arg_constraint' is 
out of the accepted range; It should be a buffer with size equal to or greater 
than the value of the 2nd argument}}
+    // expected-warning{{The 1st argument to '__buf_size_arg_constraint' is a 
buffer with size 3 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) [}}
     break;
   }
   case 3: {
     char buf[3];
     __buf_size_arg_constraint_mul(buf, 4, 2); // \
-    // expected-warning{{The 1st argument to '__buf_size_arg_constraint_mul' 
is out of the accepted range; It should be a buffer with size equal to or 
greater than the value of the 2nd argument times the 3rd argument}}
+    // expected-warning{{The 1st argument to '__buf_size_arg_constraint_mul' 
is a buffer with size 3 but should be a buffer with size equal to or greater 
than the value of the 2nd argument (which is 4) times the 3rd argument (which 
is 2) [}}
     break;
   }
   }

diff  --git 
a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c 
b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
index b2377363dbb6..766b0c58910c 100644
--- 
a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
+++ 
b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
@@ -16,8 +16,8 @@ void test_buf_size_concrete(void) {
   char buf[3];                       // bugpath-note{{'buf' initialized here}}
   int s = 4;                         // bugpath-note{{'s' initialized to 4}}
   __buf_size_arg_constraint(buf, s); // \
-  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is out 
of the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument}} \
-  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is out of 
the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument}}
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is a 
buffer with size 3 but should be a buffer with size equal to or greater than 
the value of the 2nd argument}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is a buffer 
with size 3 but should be a buffer with size equal to or greater than the value 
of the 2nd argument}}
 }
 
 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
@@ -26,6 +26,6 @@ void test_buf_size_concrete_with_multiplication(void) {
   int s1 = 4;                                 // bugpath-note{{'s1' 
initialized to 4}}
   int s2 = sizeof(short);                     // bugpath-note{{'s2' 
initialized to}}
   __buf_size_arg_constraint_mul(buf, s1, s2); // \
-  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is 
out of the accepted range; It should be a buffer with size equal to or greater 
than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is out 
of the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument times the 3rd argument}}
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a 
buffer with size 6 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) times the 3rd argument (which is 
2)}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is a 
buffer with size 6 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}}
 }

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c 
b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
index 981318c755e1..615f84047af5 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -210,9 +210,9 @@ void ARR38_C_F(FILE *file) {
   // The 3rd parameter should be the number of elements to read, not
   // the size in bytes.
   fread(wbuf, size, nitems, file); // \
-  // report-warning{{The 1st argument to 'fread' is out of the accepted range; 
It should be a buffer with size equal to or greater than the value of the 2nd 
argument times the 3rd argument}} \
-  // bugpath-warning{{The 1st argument to 'fread' is out of the accepted 
range; It should be a buffer with size equal to or greater than the value of 
the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The 1st argument to 'fread' is out of the accepted range; 
It should be a buffer with size equal to or greater than the value of the 2nd 
argument times the 3rd argument}}
+  // report-warning{{The 1st argument to 'fread' is a buffer with size 4096 
but should be a buffer with size equal to or greater than the value of the 2nd 
argument (which is 4) times the 3rd argument (which is 4096)}} \
+  // bugpath-warning{{The 1st argument to 'fread' is a buffer with size 4096 
but should be a buffer with size equal to or greater than the value of the 2nd 
argument (which is 4) times the 3rd argument (which is 4096)}} \
+  // bugpath-note{{The 1st argument to 'fread' is a buffer with size 4096 but 
should be a buffer with size equal to or greater than the value of the 2nd 
argument (which is 4) times the 3rd argument (which is 4096)}}
 }
 
 int __two_constrained_args(int, int);
@@ -254,9 +254,9 @@ int __buf_size_arg_constraint(const void *, size_t);
 void test_buf_size_concrete(void) {
   char buf[3];                       // bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint(buf, 4); // \
-  // report-warning{{The 1st argument to '__buf_size_arg_constraint' is out of 
the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument}} \
-  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is out 
of the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument}} \
-  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is out of 
the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint' is a 
buffer with size 3 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4)}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is a 
buffer with size 3 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4)}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is a buffer 
with size 3 but should be a buffer with size equal to or greater than the value 
of the 2nd argument (which is 4)}}
 }
 void test_buf_size_symbolic(int s) {
   char buf[3];
@@ -281,9 +281,9 @@ int __buf_size_arg_constraint_mul(const void *, size_t, 
size_t);
 void test_buf_size_concrete_with_multiplication(void) {
   short buf[3];                                         // bugpath-note{{'buf' 
initialized here}}
   __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
-  // report-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is 
out of the accepted range; It should be a buffer with size equal to or greater 
than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is 
out of the accepted range; It should be a buffer with size equal to or greater 
than the value of the 2nd argument times the 3rd argument}} \
-  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is out 
of the accepted range; It should be a buffer with size equal to or greater than 
the value of the 2nd argument times the 3rd argument}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a 
buffer with size 6 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) times the 3rd argument (which is 
2)}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a 
buffer with size 6 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) times the 3rd argument (which is 
2)}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is a 
buffer with size 6 but should be a buffer with size equal to or greater than 
the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}}
 }
 void test_buf_size_symbolic_with_multiplication(size_t s) {
   short buf[3];
@@ -307,9 +307,9 @@ int __buf_size_arg_constraint_concrete(const void *);
 void test_min_buf_size(void) {
   char buf[9];// bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint_concrete(buf); // \
-  // report-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' 
is out of the accepted range; It should be a buffer with size equal to or 
greater than 10}} \
-  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' 
is out of the accepted range; It should be a buffer with size equal to or 
greater than 10}} \
-  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_concrete' is 
out of the accepted range; It should be a buffer with size equal to or greater 
than 10}}
+  // report-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' 
is a buffer with size 9 but should be a buffer with size equal to or greater 
than 10}} \
+  // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' 
is a buffer with size 9 but should be a buffer with size equal to or greater 
than 10}} \
+  // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_concrete' is 
a buffer with size 9 but should be a buffer with size equal to or greater than 
10}}
 }
 
 void test_file_fd_at_functions() {


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to