From 72b766d5860c6c8ef25168293521dc11da6cdbd4 Mon Sep 17 00:00:00 2001 From: Sigurd Schneider Date: Thu, 2 May 2019 16:02:45 +0200 Subject: [PATCH] Merged: [builtins] Check for stack overflow in JSConstructStub Revision: 0a0d70eb8c8652c415b78feb7d8c96f9760673f0 BUG=chromium:951322 LOG=N NOTRY=true NOPRESUBMIT=true NOTREECHECKS=true R=neis@chromium.org Change-Id: If5e47223e38ae0c106932f6eca6529ae18b40c80 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1593298 Reviewed-by: Georg Neis Cr-Commit-Position: refs/branch-heads/7.5@{#16} Cr-Branched-From: 35b9bf5cf697b1c0fe4313c1313782d626d2afaa-refs/heads/7.5.288@{#1} Cr-Branched-From: 912b3912b4fc294083fadcac672571bb43c2f37e-refs/heads/master@{#60911} --- src/builtins/arm/builtins-arm.cc | 37 +++++++----- src/builtins/arm64/builtins-arm64.cc | 84 ++++++++++++++++------------ src/builtins/ia32/builtins-ia32.cc | 55 ++++++++++-------- src/builtins/x64/builtins-x64.cc | 46 +++++++++------ 4 files changed, 132 insertions(+), 90 deletions(-) diff --git a/src/builtins/arm/builtins-arm.cc b/src/builtins/arm/builtins-arm.cc index 37be51ecddb..e0a5a909788 100644 --- a/src/builtins/arm/builtins-arm.cc +++ b/src/builtins/arm/builtins-arm.cc @@ -97,6 +97,20 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm, namespace { +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Register scratch, Label* stack_overflow) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + __ LoadRoot(scratch, RootIndex::kRealStackLimit); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ sub(scratch, sp, scratch); + // Check if the arguments will overflow the stack. + __ cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); + __ b(le, stack_overflow); // Signed comparison. +} + void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : number of arguments @@ -109,6 +123,10 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { Register scratch = r2; + Label stack_overflow; + + Generate_StackOverflowCheck(masm, r0, scratch, &stack_overflow); + // Enter a construct frame. { FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT); @@ -164,20 +182,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ add(sp, sp, Operand(scratch, LSL, kPointerSizeLog2 - kSmiTagSize)); __ add(sp, sp, Operand(kPointerSize)); __ Jump(lr); -} -void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Register scratch, Label* stack_overflow) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - __ LoadRoot(scratch, RootIndex::kRealStackLimit); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ sub(scratch, sp, scratch); - // Check if the arguments will overflow the stack. - __ cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); - __ b(le, stack_overflow); // Signed comparison. + __ bind(&stack_overflow); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ bkpt(0); // Unreachable code. + } } } // namespace diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc index f814420d359..36fa0423243 100644 --- a/src/builtins/arm64/builtins-arm64.cc +++ b/src/builtins/arm64/builtins-arm64.cc @@ -92,6 +92,44 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm, namespace { +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Label* stack_overflow) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.AcquireX(); + + // Check the stack for overflow. + // We are not trying to catch interruptions (e.g. debug break and + // preemption) here, so the "real stack limit" is checked. + + __ LoadRoot(scratch, RootIndex::kRealStackLimit); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ Sub(scratch, sp, scratch); + // Check if the arguments will overflow the stack. + __ Cmp(scratch, Operand(num_args, LSL, kSystemPointerSizeLog2)); + __ B(le, stack_overflow); + +#if defined(V8_OS_WIN) + // Simulate _chkstk to extend stack guard page on Windows ARM64. + const int kPageSize = 4096; + Label chkstk, chkstk_done; + Register probe = temps.AcquireX(); + + __ Sub(scratch, sp, Operand(num_args, LSL, kSystemPointerSizeLog2)); + __ Mov(probe, sp); + + // Loop start of stack probe. + __ Bind(&chkstk); + __ Sub(probe, probe, kPageSize); + __ Cmp(probe, scratch); + __ B(lo, &chkstk_done); + __ Ldrb(xzr, MemOperand(probe)); + __ B(&chkstk); + + __ Bind(&chkstk_done); +#endif +} + void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- x0 : number of arguments @@ -103,6 +141,9 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // ----------------------------------- ASM_LOCATION("Builtins::Generate_JSConstructStubHelper"); + Label stack_overflow; + + Generate_StackOverflowCheck(masm, x0, &stack_overflow); // Enter a construct frame. { @@ -193,44 +234,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // Remove caller arguments from the stack and return. __ DropArguments(x1, TurboAssembler::kCountExcludesReceiver); __ Ret(); -} -void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Label* stack_overflow) { - UseScratchRegisterScope temps(masm); - Register scratch = temps.AcquireX(); - - // Check the stack for overflow. - // We are not trying to catch interruptions (e.g. debug break and - // preemption) here, so the "real stack limit" is checked. - - __ LoadRoot(scratch, RootIndex::kRealStackLimit); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ Sub(scratch, sp, scratch); - // Check if the arguments will overflow the stack. - __ Cmp(scratch, Operand(num_args, LSL, kSystemPointerSizeLog2)); - __ B(le, stack_overflow); - -#if defined(V8_OS_WIN) - // Simulate _chkstk to extend stack guard page on Windows ARM64. - const int kPageSize = 4096; - Label chkstk, chkstk_done; - Register probe = temps.AcquireX(); - - __ Sub(scratch, sp, Operand(num_args, LSL, kSystemPointerSizeLog2)); - __ Mov(probe, sp); - - // Loop start of stack probe. - __ Bind(&chkstk); - __ Sub(probe, probe, kPageSize); - __ Cmp(probe, scratch); - __ B(lo, &chkstk_done); - __ Ldrb(xzr, MemOperand(probe)); - __ B(&chkstk); - - __ Bind(&chkstk_done); -#endif + __ Bind(&stack_overflow); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Unreachable(); + } } } // namespace diff --git a/src/builtins/ia32/builtins-ia32.cc b/src/builtins/ia32/builtins-ia32.cc index da7f083e052..40a37b6a9ff 100644 --- a/src/builtins/ia32/builtins-ia32.cc +++ b/src/builtins/ia32/builtins-ia32.cc @@ -72,6 +72,30 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm, namespace { +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Register scratch, Label* stack_overflow, + bool include_receiver = false) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + ExternalReference real_stack_limit = + ExternalReference::address_of_real_stack_limit(masm->isolate()); + // Compute the space that is left as a negative number in scratch. If + // we already overflowed, this will be a positive number. + __ mov(scratch, __ ExternalReferenceAsOperand(real_stack_limit, scratch)); + __ sub(scratch, esp); + // Add the size of the arguments. + static_assert(kSystemPointerSize == 4, + "The next instruction assumes kSystemPointerSize == 4"); + __ lea(scratch, Operand(scratch, num_args, times_system_pointer_size, 0)); + if (include_receiver) { + __ add(scratch, Immediate(kSystemPointerSize)); + } + // See if we overflowed, i.e. scratch is positive. + __ cmp(scratch, Immediate(0)); + __ j(greater, stack_overflow); // Signed comparison. +} + void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax: number of arguments @@ -80,6 +104,10 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // -- esi: context // ----------------------------------- + Label stack_overflow; + + Generate_StackOverflowCheck(masm, eax, ecx, &stack_overflow); + // Enter a construct frame. { FrameScope scope(masm, StackFrame::CONSTRUCT); @@ -139,30 +167,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { 1 * kSystemPointerSize)); // 1 ~ receiver __ PushReturnAddressFrom(ecx); __ ret(0); -} -void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Register scratch, Label* stack_overflow, - bool include_receiver = false) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - ExternalReference real_stack_limit = - ExternalReference::address_of_real_stack_limit(masm->isolate()); - // Compute the space that is left as a negative number in scratch. If - // we already overflowed, this will be a positive number. - __ mov(scratch, __ ExternalReferenceAsOperand(real_stack_limit, scratch)); - __ sub(scratch, esp); - // Add the size of the arguments. - static_assert(kSystemPointerSize == 4, - "The next instruction assumes kSystemPointerSize == 4"); - __ lea(scratch, Operand(scratch, num_args, times_system_pointer_size, 0)); - if (include_receiver) { - __ add(scratch, Immediate(kSystemPointerSize)); + __ bind(&stack_overflow); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ int3(); // This should be unreachable. } - // See if we overflowed, i.e. scratch is positive. - __ cmp(scratch, Immediate(0)); - __ j(greater, stack_overflow); // Signed comparison. } } // namespace diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc index b5ca48698c7..bcdf5928e16 100644 --- a/src/builtins/x64/builtins-x64.cc +++ b/src/builtins/x64/builtins-x64.cc @@ -71,6 +71,25 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm, namespace { +void Generate_StackOverflowCheck( + MacroAssembler* masm, Register num_args, Register scratch, + Label* stack_overflow, + Label::Distance stack_overflow_distance = Label::kFar) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + __ LoadRoot(kScratchRegister, RootIndex::kRealStackLimit); + __ movq(scratch, rsp); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ subq(scratch, kScratchRegister); + __ sarq(scratch, Immediate(kSystemPointerSizeLog2)); + // Check if the arguments will overflow the stack. + __ cmpq(scratch, num_args); + // Signed comparison. + __ j(less_equal, stack_overflow, stack_overflow_distance); +} + void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- rax: number of arguments @@ -79,6 +98,9 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // -- rsi: context // ----------------------------------- + Label stack_overflow; + Generate_StackOverflowCheck(masm, rax, rcx, &stack_overflow, Label::kFar); + // Enter a construct frame. { FrameScope scope(masm, StackFrame::CONSTRUCT); @@ -136,25 +158,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ PushReturnAddressFrom(rcx); __ ret(0); -} -void Generate_StackOverflowCheck( - MacroAssembler* masm, Register num_args, Register scratch, - Label* stack_overflow, - Label::Distance stack_overflow_distance = Label::kFar) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - __ LoadRoot(kScratchRegister, RootIndex::kRealStackLimit); - __ movq(scratch, rsp); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ subq(scratch, kScratchRegister); - __ sarq(scratch, Immediate(kSystemPointerSizeLog2)); - // Check if the arguments will overflow the stack. - __ cmpq(scratch, num_args); - // Signed comparison. - __ j(less_equal, stack_overflow, stack_overflow_distance); + __ bind(&stack_overflow); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ int3(); // This should be unreachable. + } } } // namespace