Author: Gustas JanuĊĦonis
Date: 2026-07-03T17:49:24+02:00
New Revision: e6cef24f6c5cbae725eeba3c0fffcb15380f9d27

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

LOG: [clang-format] Fix crash on numeric literals with an incomplete exponent 
(#206594)

NumericLiteralInfo could read into tokens out of bounds due to the token
processing assuming well-formed numeric literals and incrementing
pointers to read past them. The fix properly bounds the searches to the
token size via std::min and accounts for the new trimmed string size.

Fixes #206593

Used Claude Code for help with identifying the source of the bug and
checking correctness with fuzzing, wrote the solution myself

Added: 
    

Modified: 
    clang/lib/Format/NumericLiteralInfo.cpp
    clang/unittests/Format/NumericLiteralInfoTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Format/NumericLiteralInfo.cpp 
b/clang/lib/Format/NumericLiteralInfo.cpp
index 81e6dd5e58bbc..b4d0873cdc243 100644
--- a/clang/lib/Format/NumericLiteralInfo.cpp
+++ b/clang/lib/Format/NumericLiteralInfo.cpp
@@ -16,6 +16,7 @@
 
 #include "NumericLiteralInfo.h"
 #include "llvm/ADT/StringExtras.h"
+#include <algorithm>
 
 namespace clang {
 namespace format {
@@ -46,11 +47,13 @@ NumericLiteralInfo::NumericLiteralInfo(StringRef Text, char 
Separator) {
 
   // e.g. 1.e2 or 0xFp2
   const auto Pos = DotPos != StringRef::npos ? DotPos + 1 : BaseLetterPos + 2;
+  // Trim C++ user-defined suffix as in `1_Pa`.
+  const auto TrimmedText =
+      Separator == '\'' ? Text.take_front(Text.find('_')) : Text;
 
-  ExponentLetterPos =
-      // Trim C++ user-defined suffix as in `1_Pa`.
-      (Separator == '\'' ? Text.take_front(Text.find('_')) : Text)
-          .find_insensitive(IsHex ? 'p' : 'e', Pos);
+  // Clamp searches due to possible incomplete literals.
+  ExponentLetterPos = TrimmedText.find_insensitive(
+      IsHex ? 'p' : 'e', std::min(Pos, TrimmedText.size()));
 
   const bool HasExponent = ExponentLetterPos != StringRef::npos;
   SuffixPos = Text.find_if_not(
@@ -58,7 +61,8 @@ NumericLiteralInfo::NumericLiteralInfo(StringRef Text, char 
Separator) {
         return (HasExponent || !IsHex ? isDigit : isHexDigit)(C) ||
                C == Separator;
       },
-      HasExponent ? ExponentLetterPos + 2 : Pos); // e.g. 1e-2f
+      std::min(HasExponent ? ExponentLetterPos + 2 : Pos,
+               Text.size())); // e.g. 1e-2f
 }
 
 } // namespace format

diff  --git a/clang/unittests/Format/NumericLiteralInfoTest.cpp 
b/clang/unittests/Format/NumericLiteralInfoTest.cpp
index a892cfff531e3..018123ff5ab77 100644
--- a/clang/unittests/Format/NumericLiteralInfoTest.cpp
+++ b/clang/unittests/Format/NumericLiteralInfoTest.cpp
@@ -66,6 +66,14 @@ TEST_F(NumericLiteralInfoTest, FloatingPointLiteral) {
   EXPECT_TRUE(verifyInfo(NumericLiteralInfo("0xF.Fp-9_Pa"), 1, 3, 5, 8));
 }
 
+TEST_F(NumericLiteralInfoTest, InvalidNumericLiteral) {
+  EXPECT_TRUE(verifyInfo(NumericLiteralInfo("1e"), npos, npos, 1, npos));
+  EXPECT_TRUE(verifyInfo(NumericLiteralInfo("1.0e"), npos, 1, 3, npos));
+  EXPECT_TRUE(verifyInfo(NumericLiteralInfo("0x"), 1, npos, npos, npos));
+  EXPECT_TRUE(verifyInfo(NumericLiteralInfo("0x_"), 1, npos, npos, npos));
+  EXPECT_TRUE(verifyInfo(NumericLiteralInfo("0x1p"), 1, npos, 3, npos));
+}
+
 } // namespace
 } // namespace format
 } // namespace clang


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

Reply via email to