blob: 1a08b8e69ac491ea75d446d717c4ed22e31a9b03 [file] [log] [blame]
//@ skip if $hostOS != "darwin" or $architecture == "arm" or $architecture == "x86" or not $jitTests
// Test that throw an OOM exception when compiling a pathological, but valid nested RegExp.
var failures = [];
class TestAndExpectedException
{
constructor(func, exception)
{
this.func = func;
this.exception = exception;
}
runTest()
{
try {
this.func();
failures.push("Running " + this.func + ", expected OOM exception, but didn't get one");
} catch (e) {
let errStr = e.toString();
if (errStr != this.exception)
failures.push("Running " + this.func + ", expected: \"" + this.exception + "\" but got \"" + errStr + "\"");
}
}
}
function recurseAndTest(depth, testList)
{
// Probe stack depth
try {
let result = recurseAndTest(depth + 1, testList);
if (result == 0) {
// Call the test functions with a nearly full stack.
for (const test of testList)
test.runTest();
return 1;
} else if (result < 0)
return result + 1;
else
return result;
} catch (e) {
// Go up a several frames and then call the test functions
return -24;
}
return 1;
}
let deepRE = new RegExp("((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))");
let deepGlobalRE = new RegExp(deepRE, "g");
let matchLen = 401; // The number of parens plus 1 for the whole match.
let regExpOOMError = "Error: Out of memory: Invalid regular expression: too many nested disjunctions";
testList = [];
// Test that all RegExp related APIs that compile RE's properly handle OOM.
testList.push(new TestAndExpectedException(() => { deepRE.exec("x"); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { deepRE.test("x"); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".match(deepRE); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".match(deepGlobalRE); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".replace(deepGlobalRE, ""); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".replace(deepGlobalRE, "X"); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".replace(deepGlobalRE, () => { return "X" }); }, regExpOOMError));
testList.push(new TestAndExpectedException(() => { "x".search(deepRE); }, regExpOOMError));
recurseAndTest(1, testList);
if (failures.length) {
print("Got the following failures:");
for (const failure of failures)
print(failure);
throw "Got failures";
}
// Test that the RegExp works correctly with RegExp.exec() and RegExp.test() when there is sufficient stack space to compile it.
let m = deepRE.exec("x");
let matched = true;
if (m.length != matchLen)
matched = false
else {
for (i = 0; i < matchLen; i++) {
if (m[i] != "x")
matched = false;
}
}
if (!matched) {
let expectedMatch = [];
for (i = 0; i < matchLen; i++)
expectedMatch[i] = "x";
throw "Expected RegExp.exec(...) to be [" + expectedMatch + "] but got [" + m + "]";
}
if (!deepRE.test("x"))
throw "Expected RegExp.test(...) to be true, but was false";