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'));
+ }
+}