[analyzer] Fix "sprintf" parameter modeling in CStringChecker

`CE->getCalleeDecl()` returns `VarDecl` if the callee is actually a
function pointer variable. Consequently, calling `getAsFunction()` will
return null.

To workaround the case, we should use the `CallEvent::parameters()`,
which will internally recover the function being called and do the right
thing.

Fixes #74269
Depends on "[analyzer][NFC] Prefer CallEvent over CallExpr in APIs"
This commit is contained in:
Balazs Benics 2023-12-04 17:53:23 +01:00
parent d1856b2f18
commit a49cf6c14a
3 changed files with 26 additions and 5 deletions

View File

@ -1115,6 +1115,9 @@ Crash and bug fixes
`#59493 <https://github.com/llvm/llvm-project/issues/59493>`_,
`#54533 <https://github.com/llvm/llvm-project/issues/54533>`_)
- Fixed an ``alpha.unix.cstring`` crash on variadic functions.
(`#74269 <https://github.com/llvm/llvm-project/issues/74269>`_)
- Fix false positive in mutation check when using pointer to member function.
(`#66204 <https://github.com/llvm/llvm-project/issues/66204>`_)

View File

@ -2487,8 +2487,7 @@ void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
// FIXME: We should use `Call.parameters().size()` here.
const auto NumParams = CE->getCalleeDecl()->getAsFunction()->getNumParams();
const auto NumParams = Call.parameters().size();
assert(CE->getNumArgs() >= NumParams);
const auto AllArguments =

View File

@ -1,6 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -verify %s
// expected-no-diagnostics
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection -verify %s
// Test functions that are called "memcpy" but aren't the memcpy
// we're looking for. Unfortunately, this test cannot be put into
@ -9,6 +7,11 @@
typedef __typeof(sizeof(int)) size_t;
void *memcpy(void *, const void *, size_t);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
void clang_analyzer_warnIfReached();
struct S {
static S s1, s2;
@ -26,3 +29,19 @@ void *memcpy(void *, const S &, size_t);
void test_out_of_class_weird_memcpy() {
memcpy(&S::s1, S::s2, 1); // no-crash
}
template<typename... Args>
void log(const char* fmt, const Args&... args) {
char buf[100] = {};
auto f = snprintf;
auto g = sprintf;
int n = 0;
n += f(buf, 99, fmt, args...); // no-crash: The CalleeDecl is a VarDecl, but it's okay.
n += g(buf, fmt, args...); // no-crash: Same.
(void)n;
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
}
void test_gh_74269_no_crash() {
log("%d", 1);
}