Commit 2bc09c95 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[builtins] Add stack check during generator resumption.

This fixes a corner-case where resuming a suspended generator would not
perform stack overflow checks and hence cause the stack to grow without
bounds.

R=neis@chromium.org
BUG=chromium:781583

Change-Id: Ib04116e489ac6b962cb821263860497abb57bbae
Reviewed-on: https://chromium-review.googlesource.com/765953Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49327}
parent 392ab01d
......@@ -505,6 +505,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ b(eq, &prepare_step_in_suspended_generator);
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(sp, Heap::kRealStackLimitRootIndex);
__ b(lo, &stack_overflow);
// Push receiver.
__ ldr(scratch, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset));
__ Push(scratch);
......@@ -577,6 +583,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset));
}
__ b(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bkpt(0); // This should be unreachable.
}
}
void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
......
......@@ -547,6 +547,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
&prepare_step_in_suspended_generator);
__ Bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(jssp, Heap::kRealStackLimitRootIndex);
__ B(lo, &stack_overflow);
// Get number of arguments for generator function.
__ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w10,
......@@ -630,6 +636,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
}
__ B(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable(); // This should be unreachable.
}
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
......
......@@ -534,6 +534,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ j(equal, &prepare_step_in_suspended_generator);
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
__ j(below, &stack_overflow);
// Pop return address.
__ PopReturnAddressTo(eax);
......@@ -613,6 +619,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
}
__ jmp(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ int3(); // This should be unreachable.
}
}
static void ReplaceClosureCodeWithOptimizedCode(
......
......@@ -599,6 +599,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ Branch(&prepare_step_in_suspended_generator, eq, a1, Operand(t1));
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&stack_overflow, lo, sp, Operand(at));
// Push receiver.
__ lw(t1, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset));
__ Push(t1);
......@@ -670,6 +676,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
}
__ Branch(USE_DELAY_SLOT, &stepping_prepared);
__ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ break_(0xCC); // This should be unreachable.
}
}
static void ReplaceClosureCodeWithOptimizedCode(
......
......@@ -490,6 +490,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ Branch(&prepare_step_in_suspended_generator, eq, a1, Operand(a5));
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&stack_overflow, lo, sp, Operand(at));
// Push receiver.
__ Ld(a5, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset));
__ Push(a5);
......@@ -562,6 +568,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
}
__ Branch(USE_DELAY_SLOT, &stepping_prepared);
__ Ld(a4, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ break_(0xCC); // This should be unreachable.
}
}
void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
......
......@@ -508,6 +508,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ beq(&prepare_step_in_suspended_generator);
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(sp, Heap::kRealStackLimitRootIndex);
__ blt(&stack_overflow);
// Push receiver.
__ LoadP(ip, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset));
__ Push(ip);
......@@ -578,6 +584,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset));
}
__ b(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bkpt(0); // This should be unreachable.
}
}
void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
......
......@@ -498,6 +498,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ beq(&prepare_step_in_suspended_generator);
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(sp, Heap::kRealStackLimitRootIndex);
__ blt(&stack_overflow);
// Push receiver.
__ LoadP(ip, FieldMemOperand(r3, JSGeneratorObject::kReceiverOffset));
__ Push(ip);
......@@ -573,6 +579,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ LoadP(r6, FieldMemOperand(r3, JSGeneratorObject::kFunctionOffset));
}
__ b(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bkpt(0); // This should be unreachable.
}
}
void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
......
......@@ -604,6 +604,12 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ j(equal, &prepare_step_in_suspended_generator);
__ bind(&stepping_prepared);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
__ CompareRoot(rsp, Heap::kRealStackLimitRootIndex);
__ j(below, &stack_overflow);
// Pop return address.
__ PopReturnAddressTo(rax);
......@@ -683,6 +689,13 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset));
}
__ jmp(&stepping_prepared);
__ bind(&stack_overflow);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ int3(); // This should be unreachable.
}
}
// TODO(juliana): if we remove the code below then we don't need all
......
// Copyright 2017 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: --allow-natives-syntax
function* generator(a) {
a.pop().next();
}
function prepareGenerators(n) {
var a = [{ next: () => 0 }];
for (var i = 0; i < n; ++i) {
a.push(generator(a));
}
return a;
}
var gens1 = prepareGenerators(10);
assertDoesNotThrow(() => gens1.pop().next());
%OptimizeFunctionOnNextCall(generator);
var gens2 = prepareGenerators(200000);
assertThrows(() => gens2.pop().next(), RangeError);
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