From 9d335059fb915ff76fdad3a88f21f50740e88842 Mon Sep 17 00:00:00 2001 From: reginaldalfret Date: Fri, 23 Oct 2026 19:54:42 +0530 Subject: [PATCH] Replace recursive regex in PhoneNumberUtil.normalize() with linear scan PR #4017 replaced VALID_ALPHA_PHONE_PATTERN with hasAtLeastThreeAlphaChars() in PhoneNumberUtil.isAlphaNumber() to eliminate StackOverflowError caused by recursive evaluation on long numeric inputs in java.util.regex. However, PhoneNumberUtil.normalize(StringBuilder) still called VALID_ALPHA_PHONE_PATTERN.matcher(number).matches(), leaving normalize() vulnerable to the same recursion failure and leaving VALID_ALPHA_PHONE_PATTERN in the codebase solely for that call. This commit updates normalize(StringBuilder) to use hasAtLeastThreeAlphaChars(number) and removes the unused VALID_ALPHA_PHONE_PATTERN, fully eliminating the pattern and preventing StackOverflowError on long inputs. Also adds a regression test and updates pending_code_changes.txt. Signed-off-by: reginaldalfret --- .../com/google/i18n/phonenumbers/PhoneNumberUtil.java | 7 +------ .../google/i18n/phonenumbers/PhoneNumberUtilTest.java | 9 +++++++++ pending_code_changes.txt | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index a1d83b3070..d741b0938b 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -277,10 +277,6 @@ public class PhoneNumberUtil { private static final String UNWANTED_END_CHARS = "[[\\P{N}&&\\P{L}]&&[^#]]+$"; static final Pattern UNWANTED_END_CHAR_PATTERN = Pattern.compile(UNWANTED_END_CHARS); - // We use this pattern to check if the phone number has at least three letters in it - if so, then - // we treat it as a number where some phone-number digits are represented by letters. - private static final Pattern VALID_ALPHA_PHONE_PATTERN = Pattern.compile("(?:.*?[A-Za-z]){3}.*"); - // Regular expression of viable phone numbers. This is location independent. Checks we have at // least three leading digits, and only valid punctuation, alpha characters and // digits in the phone number. Does not include extension data. @@ -802,8 +798,7 @@ static boolean isViablePhoneNumber(CharSequence number) { * normalized in place */ static StringBuilder normalize(StringBuilder number) { - Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number); - if (m.matches()) { + if (hasAtLeastThreeAlphaChars(number)) { number.replace(0, number.length(), normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true)); } else { number.replace(0, number.length(), normalizeDigitsOnly(number)); diff --git a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java index 4da210ec1d..c7bd7f224e 100644 --- a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java +++ b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java @@ -476,6 +476,15 @@ public void testNormaliseOtherDigits() { expectedOutput, PhoneNumberUtil.normalize(inputNumber).toString()); } + public void testNormaliseLongNumericInputDoesNotThrow() { + StringBuilder inputNumber = new StringBuilder("+"); + for (int i = 0; i < 5000; i++) { + inputNumber.append('1'); + } + // Should not throw StackOverflowError and correctly normalize digits. + assertEquals(5000, PhoneNumberUtil.normalize(inputNumber).length()); + } + public void testNormaliseStripAlphaCharacters() { String inputNumber = "034-56&+a#234"; String expectedOutput = "03456234"; diff --git a/pending_code_changes.txt b/pending_code_changes.txt index 8b13789179..d312202c83 100644 --- a/pending_code_changes.txt +++ b/pending_code_changes.txt @@ -1 +1,2 @@ - +Code changes: + - Fixed PhoneNumberUtil.normalize(StringBuilder) in Java to use a linear character scan instead of the recursive VALID_ALPHA_PHONE_PATTERN regex, preventing StackOverflowError on long inputs.