Commit 0793bb84 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[regexp] Allow heap allocation on stack overflows

The regexp interpreter holds several unhandlified references to heap
objects, and is thus within a DisallowHeapAllocation scope. But there
are two situations in which we can and do allocate safely:

1. When creating & throwing a stack overflow exception. The interpreter
   aborts afterwards, and thus possible-moved objects are never used.
2. When handling interrupts. We manually relocate unhandlified references
   after interrupts have run.

This CL explicitly allows allocations on stack overflows.

Isolate::StackOverflow allocates heap objects.

Bug: chromium:940722, v8:8724
Change-Id: I74ef6f0dd7a30bd55f49a7bc0f2f6ac82adbeda8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1518174Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60191}
parent 88401186
...@@ -149,6 +149,14 @@ class BacktrackStack { ...@@ -149,6 +149,14 @@ class BacktrackStack {
namespace { namespace {
IrregexpInterpreter::Result StackOverflow(Isolate* isolate) {
// We abort interpreter execution after the stack overflow is thrown, and thus
// allow allocation here despite the outer DisallowHeapAllocationScope.
AllowHeapAllocation yes_gc;
isolate->StackOverflow();
return IrregexpInterpreter::EXCEPTION;
}
// Runs all pending interrupts. Callers must update unhandlified object // Runs all pending interrupts. Callers must update unhandlified object
// references after this function completes. // references after this function completes.
IrregexpInterpreter::Result HandleInterrupts(Isolate* isolate, IrregexpInterpreter::Result HandleInterrupts(Isolate* isolate,
...@@ -158,9 +166,7 @@ IrregexpInterpreter::Result HandleInterrupts(Isolate* isolate, ...@@ -158,9 +166,7 @@ IrregexpInterpreter::Result HandleInterrupts(Isolate* isolate,
StackLimitCheck check(isolate); StackLimitCheck check(isolate);
if (check.JsHasOverflowed()) { if (check.JsHasOverflowed()) {
// A real stack overflow. // A real stack overflow.
AllowHeapAllocation yes_gc; return StackOverflow(isolate);
isolate->StackOverflow();
return IrregexpInterpreter::EXCEPTION;
} }
const bool was_one_byte = const bool was_one_byte =
...@@ -236,24 +242,21 @@ IrregexpInterpreter::Result RawMatch(Isolate* isolate, ...@@ -236,24 +242,21 @@ IrregexpInterpreter::Result RawMatch(Isolate* isolate,
UNREACHABLE(); UNREACHABLE();
BYTECODE(PUSH_CP) BYTECODE(PUSH_CP)
if (--backtrack_stack_space < 0) { if (--backtrack_stack_space < 0) {
isolate->StackOverflow(); return StackOverflow(isolate);
return IrregexpInterpreter::EXCEPTION;
} }
*backtrack_sp++ = current; *backtrack_sp++ = current;
pc += BC_PUSH_CP_LENGTH; pc += BC_PUSH_CP_LENGTH;
break; break;
BYTECODE(PUSH_BT) BYTECODE(PUSH_BT)
if (--backtrack_stack_space < 0) { if (--backtrack_stack_space < 0) {
isolate->StackOverflow(); return StackOverflow(isolate);
return IrregexpInterpreter::EXCEPTION;
} }
*backtrack_sp++ = Load32Aligned(pc + 4); *backtrack_sp++ = Load32Aligned(pc + 4);
pc += BC_PUSH_BT_LENGTH; pc += BC_PUSH_BT_LENGTH;
break; break;
BYTECODE(PUSH_REGISTER) BYTECODE(PUSH_REGISTER)
if (--backtrack_stack_space < 0) { if (--backtrack_stack_space < 0) {
isolate->StackOverflow(); return StackOverflow(isolate);
return IrregexpInterpreter::EXCEPTION;
} }
*backtrack_sp++ = registers[insn >> BYTECODE_SHIFT]; *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
pc += BC_PUSH_REGISTER_LENGTH; pc += BC_PUSH_REGISTER_LENGTH;
...@@ -665,7 +668,13 @@ IrregexpInterpreter::Result IrregexpInterpreter::Match( ...@@ -665,7 +668,13 @@ IrregexpInterpreter::Result IrregexpInterpreter::Match(
Handle<String> subject_string, int* registers, int start_position) { Handle<String> subject_string, int* registers, int start_position) {
DCHECK(subject_string->IsFlat()); DCHECK(subject_string->IsFlat());
// Note: Heap allocation *is* allowed in two situations:
// 1. When creating & throwing a stack overflow exception. The interpreter
// aborts afterwards, and thus possible-moved objects are never used.
// 2. When handling interrupts. We manually relocate unhandlified references
// after interrupts have run.
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
uc16 previous_char = '\n'; uc16 previous_char = '\n';
String::FlatContent subject_content = subject_string->GetFlatContent(no_gc); String::FlatContent subject_content = subject_string->GetFlatContent(no_gc);
if (subject_content.IsOneByte()) { if (subject_content.IsOneByte()) {
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --stack-size=100
var __v_27278 = "x";
for (var __v_27279 = 0; __v_27279 != 13; __v_27279++) {
try { __v_27278 += __v_27278; } catch (e) {}
}
// Can throw or not, but should not crash.
try { /(xx|x)*/.exec(__v_27278); } catch (e) {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment