diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d3f352c6aabe7..e21ec78a1e8a7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1115,6 +1115,9 @@ Crash and bug fixes `#59493 `_, `#54533 `_) +- Fixed an ``alpha.unix.cstring`` crash on variadic functions. + (`#74269 `_) + - Fix false positive in mutation check when using pointer to member function. (`#66204 `_) diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index f5dbf9d82beee..b7b64c3da4f6c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -2487,8 +2487,7 @@ void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallEvent &Call, const auto *CE = cast(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 = diff --git a/clang/test/Analysis/string.cpp b/clang/test/Analysis/string.cpp index f86416da6ee23..1be6c21466cc0 100644 --- a/clang/test/Analysis/string.cpp +++ b/clang/test/Analysis/string.cpp @@ -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 +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); +}