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
