[clang] [clang-format] Fix crash on numeric literals with an incomplete exponent (PR #206594)
Gustas JanuĊĦonis via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 14:53:43 PDT 2026
https://github.com/LeGusto created https://github.com/llvm/llvm-project/pull/206594
NumericLiteralInfo computed the exponent/suffix search start from positions that can exceed the length of the string being searched (e.g. for `1e`, `1.0e`, `0xa.p`, `0x`, or `0x_`), so StringRef::find_insensitive and find_if_not read out of bounds -- an assertion failure on assertions-enabled builds and a silent out-of-bounds read otherwise. Clamp each search start to the length of the string it indexes.
Fixes #206593
>From 2012d864779c8a80e248e0c068db6dcf4f1bd2cb Mon Sep 17 00:00:00 2001
From: LeGusto <janusonis.gustas at gmail.com>
Date: Tue, 30 Jun 2026 00:42:16 +0300
Subject: [PATCH] [clang-format] Fix crash on numeric literals with an
incomplete exponent
NumericLiteralInfo computed the exponent/suffix search start from positions that can exceed the length of the string being searched (e.g. for `1e`, `1.0e`, `0xa.p`, `0x`, or `0x_`), so StringRef::find_insensitive and find_if_not read out of bounds -- an assertion failure on assertions-enabled builds and a silent out-of-bounds read otherwise. Clamp each search start to
the length of the string it indexes.
Fixes #206593
---
clang/lib/Format/NumericLiteralInfo.cpp | 14 +++++++++-----
clang/unittests/Format/NumericLiteralCaseTest.cpp | 11 +++++++++++
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Format/NumericLiteralInfo.cpp b/clang/lib/Format/NumericLiteralInfo.cpp
index 81e6dd5e58bbc..0bd27f50efa8c 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
+ HasExponent ? std::min(ExponentLetterPos + 2, Text.size())
+ : std::min(Pos, Text.size())); // e.g. 1e-2f
}
} // namespace format
diff --git a/clang/unittests/Format/NumericLiteralCaseTest.cpp b/clang/unittests/Format/NumericLiteralCaseTest.cpp
index ecd230d73f692..afb321d8d1b14 100644
--- a/clang/unittests/Format/NumericLiteralCaseTest.cpp
+++ b/clang/unittests/Format/NumericLiteralCaseTest.cpp
@@ -340,6 +340,17 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
}
+TEST_F(NumericLiteralCaseTest, IncompleteLiteralDoesNotCrash) {
+ auto Style = getLLVMStyle();
+ Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
+
+ verifyFormat("i = 1e;", Style);
+ verifyFormat("i = 1.0e;", Style);
+ verifyFormat("i = 0x1p;", Style);
+ verifyFormat("i = 0x;", Style);
+ verifyFormat("i = 0x_;", Style);
+}
+
} // namespace
} // namespace test
} // namespace format
More information about the cfe-commits
mailing list