Skip to content

Commit e97a8fa

Browse files
committed
8300207: Add a pre-check for the number of canonical equivalent permutations in j.u.r.Pattern
Reviewed-by: phh Backport-of: 030b071db1fb6197a2633a04b20aa95432a903bc
1 parent cfddb16 commit e97a8fa

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

src/java.base/share/classes/java/util/regex/Pattern.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1090,6 +1090,10 @@ public static Pattern compile(String regex) {
10901090
*
10911091
* @throws PatternSyntaxException
10921092
* If the expression's syntax is invalid
1093+
*
1094+
* @implNote If {@link #CANON_EQ} is specified and the number of combining
1095+
* marks for any character is too large, an {@link java.lang.OutOfMemoryError}
1096+
* is thrown.
10931097
*/
10941098
public static Pattern compile(String regex, int flags) {
10951099
return new Pattern(regex, flags);
@@ -1123,6 +1127,13 @@ public String toString() {
11231127
* The character sequence to be matched
11241128
*
11251129
* @return A new matcher for this pattern
1130+
*
1131+
* @implNote When a {@link Pattern} is deserialized, compilation is deferred
1132+
* until a direct or indirect invocation of this method. Thus, if a
1133+
* deserialized pattern has {@link #CANON_EQ} among its flags and the number
1134+
* of combining marks for any character is too large, an
1135+
* {@link java.lang.OutOfMemoryError} is thrown,
1136+
* as in {@link #compile(String, int)}.
11261137
*/
11271138
public Matcher matcher(CharSequence input) {
11281139
if (!compiled) {
@@ -1596,14 +1607,30 @@ private static String[] producePermutations(String input) {
15961607
return result;
15971608
}
15981609

1599-
int length = 1;
1610+
/*
1611+
* Since
1612+
* 12! = 479_001_600 < Integer.MAX_VALUE
1613+
* 13! = 6_227_020_800 > Integer.MAX_VALUE
1614+
* the computation of n! using int arithmetic will overflow iff
1615+
* n < 0 or n > 12
1616+
*
1617+
* Here, nCodePoints! is computed in the next for-loop below.
1618+
* As nCodePoints >= 0, the computation overflows iff nCodePoints > 12.
1619+
* In that case, throw OOME to simulate length > Integer.MAX_VALUE.
1620+
*/
16001621
int nCodePoints = countCodePoints(input);
1601-
for(int x=1; x<nCodePoints; x++)
1602-
length = length * (x+1);
1622+
if (nCodePoints > 12) {
1623+
throw new OutOfMemoryError("Pattern too complex");
1624+
}
16031625

1626+
/* Compute length = nCodePoints! */
1627+
int length = 1;
1628+
for (int x = 2; x <= nCodePoints; ++x) {
1629+
length *= x;
1630+
}
16041631
String[] temp = new String[length];
16051632

1606-
int combClass[] = new int[nCodePoints];
1633+
int[] combClass = new int[nCodePoints];
16071634
for(int x=0, i=0; x<nCodePoints; x++) {
16081635
int c = Character.codePointAt(input, i);
16091636
combClass[x] = getClass(c);

0 commit comments

Comments
 (0)