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-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new e2838b281 StringUtils.indexOfAny(CharSequence, int, char...) should 
not throw for a bad index (#1656)
e2838b281 is described below

commit e2838b281f874302856114e75767fb24799e0cca
Author: Gary Gregory <[email protected]>
AuthorDate: Sun May 17 19:24:07 2026 -0400

    StringUtils.indexOfAny(CharSequence, int, char...) should not throw for a 
bad index (#1656)
---
 .../java/org/apache/commons/lang3/StringUtils.java |  2 +-
 .../commons/lang3/StringUtilsIndexOfAnyTest.java   | 68 ++++++++++++++++++++++
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java 
b/src/main/java/org/apache/commons/lang3/StringUtils.java
index 1b92bbab9..99ef00ff9 100644
--- a/src/main/java/org/apache/commons/lang3/StringUtils.java
+++ b/src/main/java/org/apache/commons/lang3/StringUtils.java
@@ -2811,7 +2811,7 @@ public static int indexOfAny(final CharSequence cs, final 
int csStart, final cha
         final int csLast = csLen - 1;
         final int searchLen = searchChars.length;
         final int searchLast = searchLen - 1;
-        for (int i = csStart; i < csLen; i++) {
+        for (int i = Math.max(csStart, 0); i < csLen; i++) {
             final char ch = cs.charAt(i);
             for (int j = 0; j < searchLen; j++) {
                 if (searchChars[j] == ch) {
diff --git 
a/src/test/java/org/apache/commons/lang3/StringUtilsIndexOfAnyTest.java 
b/src/test/java/org/apache/commons/lang3/StringUtilsIndexOfAnyTest.java
new file mode 100644
index 000000000..9d528309d
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/StringUtilsIndexOfAnyTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@code StringUtils#indexOfAny(...)}} methods.
+ * <p>
+ * Negative start index can crash new indexOfAny overload.
+ * </p>
+ * <p>
+ * indexOfAny(CharSequence, int, char...) does not clamp negative csStart. 
When csStart < 0, the loop starts at a negative index causing
+ * StringIndexOutOfBoundsException.
+ * </p>
+ * <p>
+ * Pre-patch: indexOfAny("abc", -1, 'a') throws 
StringIndexOutOfBoundsException.
+ * </p>
+ * <p>
+ * Post-patch: returns 0 (clamped to 0 per StringUtils convention).
+ * </p>
+ */
+public class StringUtilsIndexOfAnyTest {
+
+    @Test
+    public void testLargeNegativeStartIndexClampsToZero() {
+        assertEquals(0, StringUtils.indexOfAny("abc", Integer.MIN_VALUE, 'a'));
+    }
+
+    @Test
+    public void testNegativeStartIndexClampsToZero() {
+        // With csStart clamped to 0, the search finds 'a' at index 0
+        assertEquals(0, StringUtils.indexOfAny("abc", -1, 'a'));
+    }
+
+    @Test
+    public void testNegativeStartIndexDoesNotThrow() {
+        assertEquals(0, StringUtils.indexOfAny("abc", -1, 'a'));
+    }
+
+    @Test
+    public void testPositiveStartIndexWorksNormally() {
+        // Start after 'a', should find 'b' at index 1
+        assertEquals(1, StringUtils.indexOfAny("abc", 1, 'b'));
+    }
+
+    @Test
+    public void testZeroStartIndexWorksNormally() {
+        assertEquals(1, StringUtils.indexOfAny("abc", 0, 'b'));
+    }
+}

Reply via email to