This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git
The following commit(s) were added to refs/heads/master by this push:
new 7bc15f1c Reject oversized Beider-Morse input before language guessing
7bc15f1c is described below
commit 7bc15f1cb49ec55919fba5b6a687a7290d330846
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Sep 18 14:31:03 2026 -0700
Reject oversized Beider-Morse input before language guessing
Check maxInputLength before language guessing in
PhoneticEngine.encode(String), avoiding unnecessary processing of inputs
that will be rejected.
Add regression tests for default, custom, and zero limits through the
engine and encoder wrapper. Update the null-input test documentation.
---
src/changes/changes.xml | 1 +
.../commons/codec/language/bm/PhoneticEngine.java | 5 +++++
.../language/bm/PhoneticEngineBuilderTest.java | 3 +--
.../codec/language/bm/PhoneticEngineTest.java | 26 ++++++++++++++++++++++
4 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index b35320e7..a78da67f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -63,6 +63,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Gary Gregory">Hex decoding now
accepts only ASCII hexadecimal characters (0-9, A-F, a-f). Previously accepted
non-ASCII Unicode digits and fullwidth letters now cause DecoderException,
including when supplied as UTF-8 bytes or ByteBuffers.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Restrict Hex
decoding to ASCII hexadecimal characters.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Validate
BinaryCodec input while preserving leading-bit truncation.</action>
+ <action type="fix" dev="ggregory" due-to="Gary Gregory">Reject oversized
Beider-Morse input before language guessing.</action>
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary Gregory">Add and use
PhoneticEngine.Builder and deprecate old constructors.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add
BeiderMorseEncoder.Builder and deprecate old constructor.</action>
diff --git
a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
index e4ca8a75..dc355eb3 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
@@ -476,6 +476,11 @@ public class PhoneticEngine {
* @throws IllegalArgumentException if the input is longer than the
maximum allowed length.
*/
public String encode(final String input) {
+ // enforce the input length limit before language guessing runs over
the input,
+ // so over-limit input cannot buy a full multi-pass scan before the
guard fires
+ if (input.length() > maxInputLength) {
+ throw new IllegalArgumentException("Input is greater than
maxInputLength (" + maxInputLength + ").");
+ }
return encode(input, lang.guessLanguages(input));
}
diff --git
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
index ee80d081..23d52c77 100644
---
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
+++
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
@@ -289,12 +289,11 @@ class PhoneticEngineBuilderTest {
/**
* Tests {@link PhoneticEngine.Builder#setMaxInputLength(int)} with a
limit of 0:
- * null input bypasses the length check but causes a {@link
NullPointerException} downstream.
+ * null input causes a {@link NullPointerException}.
*/
@Test
void testSetMaxInputLengthZeroNullInputThrowsNpe() {
final PhoneticEngine engine =
PhoneticEngine.builder().setMaxInputLength(0).get();
- // null is not blocked by the length check, but encoding null causes
NPE
assertThrows(NullPointerException.class, () -> engine.encode(null));
}
diff --git
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java
index edcb87ed..a49628be 100644
--- a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java
+++ b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java
@@ -18,14 +18,18 @@
package org.apache.commons.codec.language.bm;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.lang.reflect.Field;
+import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
/**
* Tests PhoneticEngine.
@@ -96,4 +100,26 @@ class PhoneticEngineTest {
assertEquals(engine.encode(input), phoneticExpected);
}
+
+ @ParameterizedTest
+ @ValueSource(ints = { -1, 0, 10, 666 })
+ void testRejectsOversizedInputBeforeLanguageGuessing(final int
configuredLimit) throws Exception {
+ final PhoneticEngine engine =
PhoneticEngine.builder().setMaxInputLength(configuredLimit).get();
+ final int limit = configuredLimit < 0 ? 666 : configuredLimit;
+ final char[] chars = new char[limit + 1];
+ Arrays.fill(chars, 'a');
+ final String input = new String(chars);
+
+ // Make language guessing fail if reached, without changing the shared
Lang instance or relying on timing.
+ final Field langField = PhoneticEngine.class.getDeclaredField("lang");
+ langField.setAccessible(true);
+ langField.set(engine, null);
+ assertThrows(NullPointerException.class, () ->
engine.encode(input.substring(1)));
+
+ final String message = "Input is greater than maxInputLength (" +
limit + ").";
+ assertEquals(message, assertThrows(IllegalArgumentException.class, ()
-> engine.encode(input)).getMessage());
+ assertEquals(message, assertThrows(IllegalArgumentException.class, ()
-> engine.encode(input, Languages.ANY_LANGUAGE)).getMessage());
+ final BeiderMorseEncoder encoder =
BeiderMorseEncoder.builder().setPhoneticEngine(engine).get();
+ assertEquals(message, assertThrows(IllegalArgumentException.class, ()
-> encoder.encode(input)).getMessage());
+ }
}