Skip to content

Commit eabaab2

Browse files
committed
TRegex: fix integer overflow in minPath and maxPath calculations
1 parent 0c6bdd1 commit eabaab2

File tree

4 files changed

+26
-8
lines changed

4 files changed

+26
-8
lines changed

regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/OracleDBTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,7 @@ public void generatedTests() {
16141614
test("(e?\\D[xg]){87,87}z", "",
16151615
"axaxeageagageaxeaxeaxageaxagageaxeaxagageagaxaxeagaxeaxagagaxeagageaxeaxeagageaxeaxagaxaxaxageageagageagaxaxaxageaxageaxeageaxaxaxaxaxagaxagageaxeageageageaxeaxeaxageaxaxeaxeagaxagageaxeageaxeaxaxeaxageaxaxeagaxageageaz",
16161616
0, false);
1617+
test("((b\\2{1400,1400})+|)*a", "", "a", 0, true, 0, 1, 0, 0, -1, -1);
16171618
test("(a{1100,1100})\\1", "i", "a".repeat(2400), 0, true, 0, 2200, 0, 1100);
16181619
test("[a]\\S{213,213}bcdz", "", "a".repeat(215) + ("bcxd" + "a".repeat(213)).repeat(3), 0, false);
16191620

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/CalcASTPropsVisitor.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import com.oracle.truffle.regex.tregex.buffer.CompilationBuffer;
5656
import com.oracle.truffle.regex.tregex.parser.ast.visitors.DepthFirstTraversalRegexASTVisitor;
5757
import com.oracle.truffle.regex.tregex.string.Encodings;
58+
import com.oracle.truffle.regex.tregex.util.MathUtil;
5859

5960
/**
6061
* This visitor computes various properties of {@link RegexAST} and its {@link RegexASTNode}s, in
@@ -184,7 +185,7 @@ protected void visit(BackReference backReference) {
184185
backReference.getParent().setHasBackReferences();
185186

186187
int minWidth = 0;
187-
if (ast.getFlavor().backreferencesToUnmatchedGroupsFail()) {
188+
if (ast.getFlavor().backreferencesToUnmatchedGroupsFail() && !backReference.isNestedBackReference()) {
188189
/*
189190
* Calculate the back-reference's min and max path by checking the referenced group's
190191
* min and max width. This is useful only if
@@ -339,14 +340,14 @@ protected void leave(Group group) {
339340
* summed up with min and max path of the group, so sequence.minPath - group.minPath
340341
* is the sequence's "own" minPath
341342
*/
342-
minPath = group.getMinPath() + ((minPath - group.getMinPath()) * (group.isOptionalQuantifier() ? 0 : group.getQuantifier().getMin()));
343+
minPath = MathUtil.saturatingAdd(group.getMinPath(), MathUtil.saturatingMul(minPath - group.getMinPath(), group.isOptionalQuantifier() ? 0 : group.getQuantifier().getMin()));
343344
if (group.getQuantifier().isInfiniteLoop()) {
344345
flags |= RegexASTNode.FLAG_HAS_LOOPS;
345346
// Just increase maxPath by one loop iteration; It's enough to determine
346347
// whether a given sub-expression is fixed-width.
347-
maxPath = group.getMaxPath() + ((maxPath - group.getMaxPath()) * (group.getQuantifier().getMin() + 1));
348+
maxPath = MathUtil.saturatingAdd(group.getMaxPath(), MathUtil.saturatingMul(maxPath - group.getMaxPath(), MathUtil.saturatingInc(group.getQuantifier().getMin())));
348349
} else {
349-
maxPath = group.getMaxPath() + ((maxPath - group.getMaxPath()) * group.getQuantifier().getMax());
350+
maxPath = MathUtil.saturatingAdd(group.getMaxPath(), MathUtil.saturatingMul(maxPath - group.getMaxPath(), group.getQuantifier().getMax()));
350351
}
351352
}
352353
}
@@ -474,8 +475,8 @@ protected void leave(LookBehindAssertion assertion) {
474475
if (laParent instanceof LookBehindAssertion) {
475476
ast.getProperties().setNestedLookBehindAssertions();
476477
}
477-
minPath += laParent.getMinPath();
478-
maxPath += laParent.getMaxPath();
478+
minPath = MathUtil.saturatingAdd(minPath, laParent.getMinPath());
479+
maxPath = MathUtil.saturatingAdd(maxPath, laParent.getMaxPath());
479480
laParent = laParent.getSubTreeParent();
480481
}
481482
if (assertion.isLiteral()) {

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTNode.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.truffle.regex.tregex.buffer.CompilationBuffer;
4545
import com.oracle.truffle.regex.tregex.parser.ast.visitors.CopyVisitor;
4646
import com.oracle.truffle.regex.tregex.parser.ast.visitors.MarkLookBehindEntriesVisitor;
47+
import com.oracle.truffle.regex.tregex.util.MathUtil;
4748
import com.oracle.truffle.regex.tregex.util.json.Json;
4849
import com.oracle.truffle.regex.tregex.util.json.JsonConvertible;
4950
import com.oracle.truffle.regex.tregex.util.json.JsonObject;
@@ -501,6 +502,7 @@ public int getMinPath() {
501502
}
502503

503504
public void setMinPath(int n) {
505+
assert n >= 0;
504506
minPath = n;
505507
}
506508

@@ -509,14 +511,15 @@ public void incMinPath() {
509511
}
510512

511513
public void incMinPath(int n) {
512-
minPath += n;
514+
minPath = MathUtil.saturatingAdd(minPath, n);
513515
}
514516

515517
public int getMaxPath() {
516518
return maxPath;
517519
}
518520

519521
public void setMaxPath(int n) {
522+
assert n >= 0;
520523
maxPath = n;
521524
}
522525

@@ -525,7 +528,7 @@ public void incMaxPath() {
525528
}
526529

527530
public void incMaxPath(int n) {
528-
maxPath += n;
531+
maxPath = MathUtil.saturatingAdd(maxPath, n);
529532
}
530533

531534
public int getPrefixLengthMin() {

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/util/MathUtil.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,17 @@ public static int saturatingInc(int x) {
5757
}
5858
return x + 1;
5959
}
60+
61+
public static int saturatingAdd(int x, int y) {
62+
int sum = x + y;
63+
return sum < 0 ? Integer.MAX_VALUE : sum;
64+
}
65+
66+
public static int saturatingMul(int x, int y) {
67+
long r = (long) x * (long) y;
68+
if ((int) r != r) {
69+
return Integer.MAX_VALUE;
70+
}
71+
return (int) r;
72+
}
6073
}

0 commit comments

Comments
 (0)