diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index ef85d60c658ec..1d6f97f1b702c 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 getArgsToTrack() const override { std::vector 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 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 a1b956e009f40..156b80a5488ac 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 b2377363dbb63..766b0c58910cb 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 981318c755e1e..615f84047af59 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() {