8224789: Parsing repetition count in regex does not detect numeric overflow
authorigerasim
Wed, 29 May 2019 13:44:27 -0700
changeset 55096 234673929e0a
parent 55095 3e5dba06a663
child 55097 ae908641e726
8224789: Parsing repetition count in regex does not detect numeric overflow Reviewed-by: rriggs, bchristi
src/java.base/share/classes/java/util/regex/Pattern.java
test/jdk/java/util/regex/RegExTest.java
--- a/src/java.base/share/classes/java/util/regex/Pattern.java	Wed May 29 13:39:08 2019 -0700
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java	Wed May 29 13:44:27 2019 -0700
@@ -3271,28 +3271,33 @@
         case '+':
             return curly(prev, 1);
         case '{':
-            ch = temp[cursor+1];
+            ch = skip();
             if (ASCII.isDigit(ch)) {
-                skip();
-                int cmin = 0;
-                do {
-                    cmin = cmin * 10 + (ch - '0');
-                } while (ASCII.isDigit(ch = read()));
-                int cmax = cmin;
-                if (ch == ',') {
-                    ch = read();
-                    cmax = MAX_REPS;
-                    if (ch != '}') {
-                        cmax = 0;
-                        while (ASCII.isDigit(ch)) {
-                            cmax = cmax * 10 + (ch - '0');
-                            ch = read();
+                int cmin = 0, cmax;
+                try {
+                    do {
+                        cmin = Math.addExact(Math.multiplyExact(cmin, 10),
+                                             ch - '0');
+                    } while (ASCII.isDigit(ch = read()));
+                    cmax = cmin;
+                    if (ch == ',') {
+                        ch = read();
+                        cmax = MAX_REPS;
+                        if (ch != '}') {
+                            cmax = 0;
+                            while (ASCII.isDigit(ch)) {
+                                cmax = Math.addExact(Math.multiplyExact(cmax, 10),
+                                                     ch - '0');
+                                ch = read();
+                            }
                         }
                     }
+                } catch (ArithmeticException ae) {
+                    throw error("Illegal repetition range");
                 }
                 if (ch != '}')
                     throw error("Unclosed counted closure");
-                if (((cmin) | (cmax) | (cmax - cmin)) < 0)
+                if (cmax < cmin)
                     throw error("Illegal repetition range");
                 Curly curly;
                 ch = peek();
--- a/test/jdk/java/util/regex/RegExTest.java	Wed May 29 13:39:08 2019 -0700
+++ b/test/jdk/java/util/regex/RegExTest.java	Wed May 29 13:44:27 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
  * 8027645 8035076 8039124 8035975 8074678 6854417 8143854 8147531 7071819
  * 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895
  * 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706
- * 8194667 8197462 8184692 8221431
+ * 8194667 8197462 8184692 8221431 8224789
  *
  * @library /test/lib
  * @library /lib/testlibrary/java/lang
@@ -44,15 +44,28 @@
  * @key randomness
  */
 
-import java.util.function.Function;
-import java.util.regex.*;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.nio.CharBuffer;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Random;
 import java.util.Scanner;
-import java.io.*;
-import java.nio.file.*;
-import java.util.*;
-import java.nio.CharBuffer;
+import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.MatchResult;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
 import jdk.test.lib.RandomFactory;
 
 /**
@@ -171,6 +184,7 @@
         grapheme();
         expoBacktracking();
         invalidGroupName();
+        illegalRepetitionRange();
 
         if (failure) {
             throw new
@@ -4932,4 +4946,31 @@
         }
         report("Invalid capturing group names");
     }
+
+    private static void illegalRepetitionRange() {
+        // huge integers > (2^31 - 1)
+        String n = BigInteger.valueOf(1L << 32)
+            .toString();
+        String m = BigInteger.valueOf(1L << 31)
+            .add(new BigInteger(80, generator))
+            .toString();
+        for (String rep : List.of("", "x", ".", ",", "-1", "2,1",
+                n, n + ",", "0," + n, n + "," + m, m, m + ",", "0," + m)) {
+            String pat = ".{" + rep + "}";
+            try {
+                Pattern.compile(pat);
+                failCount++;
+                System.out.println("Expected to fail. Pattern: " + pat);
+            } catch (PatternSyntaxException e) {
+                if (!e.getMessage().startsWith("Illegal repetition")) {
+                    failCount++;
+                    System.out.println("Unexpected error message: " + e.getMessage());
+                }
+            } catch (Throwable t) {
+                failCount++;
+                System.out.println("Unexpected exception: " + t);
+            }
+        }
+        report("illegalRepetitionRange");
+    }
 }