Author: fanningpj
Date: Thu Jun 18 14:23:31 2026
New Revision: 1935475

Log:
fix out-of-bounds read in RANGE op of RegularExpression.match. Thanks to 
aizu-m. This closes #58

Modified:
   
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/regex/RegularExpression.java
   xmlbeans/trunk/src/test/java/misc/checkin/RegularExpressionTest.java

Modified: 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/regex/RegularExpression.java
==============================================================================
--- 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/regex/RegularExpression.java
  Thu Jun 18 13:18:53 2026        (r1935474)
+++ 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/regex/RegularExpression.java
  Thu Jun 18 14:23:31 2026        (r1935475)
@@ -647,7 +647,7 @@ public class RegularExpression implement
      * @return true if the target is matched to this regular expression.
      */
     public boolean matches(char[]  target) {
-        return this.matches(target, 0,  target .length , (Match)null);
+        return this.matches(target, 0,  target .length , null);
     }
 
     /**
@@ -659,7 +659,7 @@ public class RegularExpression implement
      * @return true if the target is matched to this regular expression.
      */
     public boolean matches(char[]  target, int start, int end) {
-        return this.matches(target, start, end, (Match)null);
+        return this.matches(target, start, end, null);
     }
 
     /**
@@ -833,7 +833,7 @@ public class RegularExpression implement
      * @return true if the target is matched to this regular expression.
      */
     public boolean matches(String  target) {
-        return this.matches(target, 0,  target .length() , (Match)null);
+        return this.matches(target, 0,  target .length() , null);
     }
 
     /**
@@ -845,7 +845,7 @@ public class RegularExpression implement
      * @return true if the target is matched to this regular expression.
      */
     public boolean matches(String  target, int start, int end) {
-        return this.matches(target, start, end, (Match)null);
+        return this.matches(target, start, end, null);
     }
 
     /**
@@ -1023,7 +1023,7 @@ public class RegularExpression implement
      */
     private int match(Context con, Op op, int offset, int dx, int opts) {
         final ExpressionTarget target = con.target;
-        final Stack opStack = new Stack();
+        final Stack<Op> opStack = new Stack<>();
         final IntStack dataStack = new IntStack();
         final boolean isSetIgnoreCase = isSet(opts, IGNORE_CASE);
         int retValue = -1;
@@ -1091,7 +1091,7 @@ public class RegularExpression implement
                             returned = true;
                             break;
                         }
-                        int ch = target.charAt(offset);
+                        int ch = target.charAt(o1);
                         if (REUtil.isHighSurrogate(ch) && o1+dx < con.limit && 
o1+dx >=0) {
                             o1 += dx;
                             ch = REUtil.composeFromSurrogates(ch, 
target.charAt(o1));
@@ -1304,7 +1304,7 @@ public class RegularExpression implement
                     return retValue;
                 }
 
-                op = (Op) opStack.pop();
+                op = opStack.pop();
                 offset = dataStack.pop();
 
                 switch (op.type) {
@@ -1534,7 +1534,7 @@ public class RegularExpression implement
      * @return true if the target is matched to this regular expression.
      */
     public boolean matches(CharacterIterator target) {
-        return this.matches(target, (Match)null);
+        return this.matches(target, null);
     }
 
 
@@ -2401,8 +2401,7 @@ public class RegularExpression implement
         if (ch <= '9')  return true;
         if (ch < 'A')  return false;
         if (ch <= 'Z')  return true;
-        if (ch < 'a')  return false;
-        return true;
+        return ch >= 'a';
     }
 
     private static boolean matchIgnoreCase(int chardata, int ch) {

Modified: xmlbeans/trunk/src/test/java/misc/checkin/RegularExpressionTest.java
==============================================================================
--- xmlbeans/trunk/src/test/java/misc/checkin/RegularExpressionTest.java        
Thu Jun 18 13:18:53 2026        (r1935474)
+++ xmlbeans/trunk/src/test/java/misc/checkin/RegularExpressionTest.java        
Thu Jun 18 14:23:31 2026        (r1935475)
@@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test;
 
 import java.util.Random;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class RegularExpressionTest {
@@ -31,6 +32,18 @@ public class RegularExpressionTest {
         assertTrue(regex.matches(rnd));
     }
 
+    @Test
+    void testLookbehindRangeAtInputEnd() {
+        // a lookbehind containing a character class, evaluated at the end of 
the
+        // input, used to read one character past the string in the RANGE op 
and
+        // throw StringIndexOutOfBoundsException
+        assertTrue(new RegularExpression("(?<=[a-c])$").matches("abc"));
+        assertTrue(new RegularExpression(".*(?<=[0-9])").matches("ab9"));
+        // the same off-by-one read also returned the wrong match result: the 
char
+        // before the lookbehind is 'x', not in [a-c], so this must not match
+        assertFalse(new RegularExpression("x(?<=[a-c])").matches("xc"));
+    }
+
 
     private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     private static final Random rnd = new Random();

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to