Author: flovent
Date: 2025-12-17T09:56:38-08:00
New Revision: b5dd6cc7464279f9bdb7ce4cc2cec162df7aad6d

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

LOG: [clang][BufferUsage] Fix crash when parsing invalid format string (#170496)

`clang::analyze_format_string::ParsePrintfString` also returns `true`
when we get an invalid or erroneous format string, so `UnsafeArg` will
not be set, but `hasUnsafeFormatOrSArg`'s caller assumes `UnsafeArg`
will be valid when it returns true, which leads to crash.

Closes #169629

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Analysis/UnsafeBufferUsage.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 076cc1778018f..8e2e45b8ef385 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -537,6 +537,7 @@ Bug Fixes in This Version
 - Fixed false-positive shadow diagnostics for lambdas in explicit object 
member functions. (#GH163731)
 - Fix an assertion failure when a ``target_clones`` attribute is only on the
   forward declaration of a multiversioned function. (#GH165517) (#GH129483)
+- Fix a crash caused by invalid format string in printf-like functions with 
``-Wunsafe-buffer-usage-in-libc-call`` option enabled. (#GH170496)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 0b9e908517412..7ef20726d0ab9 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -834,6 +834,7 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, 
const Expr *&UnsafeArg,
     unsigned FmtArgIdx;
     const Expr *&UnsafeArg;
     ASTContext &Ctx;
+    bool UnsafeArgSet;
 
     // Returns an `Expr` representing the precision if specified, null
     // otherwise.
@@ -874,7 +875,8 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, 
const Expr *&UnsafeArg,
   public:
     StringFormatStringHandler(const CallExpr *Call, unsigned FmtArgIdx,
                               const Expr *&UnsafeArg, ASTContext &Ctx)
-        : Call(Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
+        : Call(Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
+          UnsafeArgSet(false) {}
 
     bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
                                const char *startSpecifier,
@@ -912,8 +914,11 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, 
const Expr *&UnsafeArg,
           return true;
       // Handle unsafe case:
       UnsafeArg = Call->getArg(ArgIdx); // output
+      UnsafeArgSet = true;
       return false; // returning false stops parsing immediately
     }
+
+    bool isUnsafeArgSet() { return UnsafeArgSet; }
   };
 
   const Expr *Fmt = Call->getArg(FmtArgIdx);
@@ -924,15 +929,17 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, 
const Expr *&UnsafeArg,
       StringFormatStringHandler Handler(Call, FmtArgIdx, UnsafeArg, Ctx);
 
       return analyze_format_string::ParsePrintfString(
-          Handler, FmtStr.begin(), FmtStr.end(), Ctx.getLangOpts(),
-          Ctx.getTargetInfo(), isKprintf);
+                 Handler, FmtStr.begin(), FmtStr.end(), Ctx.getLangOpts(),
+                 Ctx.getTargetInfo(), isKprintf) &&
+             Handler.isUnsafeArgSet();
     }
 
     if (auto FmtStr = SL->tryEvaluateString(Ctx)) {
       StringFormatStringHandler Handler(Call, FmtArgIdx, UnsafeArg, Ctx);
       return analyze_format_string::ParsePrintfString(
-          Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
-          Ctx.getLangOpts(), Ctx.getTargetInfo(), isKprintf);
+                 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
+                 Ctx.getLangOpts(), Ctx.getTargetInfo(), isKprintf) &&
+             Handler.isUnsafeArgSet();
     }
   }
   // If format is not a string literal, we cannot analyze the format string.

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
index b23b4acd0d1c7..4f1af79609223 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
@@ -250,3 +250,8 @@ void test(StrBuff& str)
   LibC.strcpy(buff);
   LibC.memcpy(buff, buff, 64);
 }
+
+void dontCrashForInvalidFormatString() {
+  snprintf((char*)0, 0, "%");
+  snprintf((char*)0, 0, "\0");
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to