Changeset 218869 in webkit
- Timestamp:
- Jun 28, 2017 12:11:57 AM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r218868 r218869 1 2017-06-28 Mark Lam <mark.lam@apple.com> 2 3 Ensure that computed new stack pointer values do not underflow. 4 https://bugs.webkit.org/show_bug.cgi?id=173700 5 <rdar://problem/32926032> 6 7 Reviewed by Filip Pizlo and Saam Barati. 8 9 1. Added a RELEASE_ASSERT to BytecodeGenerator::generate() to ensure that 10 m_numCalleeLocals is sane. 11 12 2. Added underflow checks in LLInt code and VarargsFrame code. 13 14 3. Introduce minimumReservedZoneSize, which is hardcoded to 16K. 15 Ensure that Options::reservedZoneSize() is at least minimumReservedZoneSize. 16 Ensure that Options::softReservedZoneSize() is at least greater than 17 Options::reservedZoneSize() by minimumReservedZoneSize. 18 19 4. Ensure that stack checks emitted by JIT tiers include an underflow check if 20 and only if the max size of the frame is greater than Options::reservedZoneSize(). 21 22 By design, we are guaranteed to have at least Options::reservedZoneSize() bytes 23 of memory at the bottom (end) of the stack. This means that, at any time, the 24 frame pointer must be at least Options::reservedZoneSize() bytes away from the 25 end of the stack. Hence, if the max frame size is less than 26 Options::reservedZoneSize(), there's no way that frame pointer - max 27 frame size can underflow, and we can elide the underflow check. 28 29 Note that we use Options::reservedZoneSize() instead of 30 Options::softReservedZoneSize() for determine if we need an underflow check. 31 This is because the softStackLimit that is used for stack checks can be set 32 based on Options::reservedZoneSize() during error handling (e.g. when creating 33 strings for instantiating the Error object). Hence, the guaranteed minimum of 34 distance between the frame pointer and the end of the stack is 35 Options::reservedZoneSize() and nor Options::softReservedZoneSize(). 36 37 Note also that we ensure that Options::reservedZoneSize() is at least 38 minimumReservedZoneSize (i.e. 16K). In typical deployments, 39 Options::reservedZoneSize() may be larger. Using Options::reservedZoneSize() 40 instead of minimumReservedZoneSize gives us more chances to elide underflow 41 checks. 42 43 * JavaScriptCore.xcodeproj/project.pbxproj: 44 * bytecompiler/BytecodeGenerator.cpp: 45 (JSC::BytecodeGenerator::generate): 46 * dfg/DFGGraph.cpp: 47 (JSC::DFG::Graph::requiredRegisterCountForExecutionAndExit): 48 * dfg/DFGJITCompiler.cpp: 49 (JSC::DFG::JITCompiler::compile): 50 (JSC::DFG::JITCompiler::compileFunction): 51 * ftl/FTLLowerDFGToB3.cpp: 52 (JSC::FTL::DFG::LowerDFGToB3::lower): 53 * jit/JIT.cpp: 54 (JSC::JIT::compileWithoutLinking): 55 * jit/SetupVarargsFrame.cpp: 56 (JSC::emitSetupVarargsFrameFastCase): 57 * llint/LLIntSlowPaths.cpp: 58 (JSC::LLInt::LLINT_SLOW_PATH_DECL): 59 * llint/LowLevelInterpreter.asm: 60 * llint/LowLevelInterpreter32_64.asm: 61 * llint/LowLevelInterpreter64.asm: 62 * runtime/MinimumReservedZoneSize.h: Added. 63 * runtime/Options.cpp: 64 (JSC::recomputeDependentOptions): 65 * runtime/VM.cpp: 66 (JSC::VM::updateStackLimits): 67 * wasm/WasmB3IRGenerator.cpp: 68 (JSC::Wasm::B3IRGenerator::B3IRGenerator): 69 * wasm/js/WebAssemblyFunction.cpp: 70 (JSC::callWebAssemblyFunction): 71 1 72 2017-06-27 JF Bastien <jfbastien@apple.com> 2 73 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r218784 r218869 2439 2439 FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; }; 2440 2440 FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2441 FE2A87601F02381600EB31B2 /* MinimumReservedZoneSize.h in Headers */ = {isa = PBXBuildFile; fileRef = FE2A875F1F02381600EB31B2 /* MinimumReservedZoneSize.h */; }; 2441 2442 FE2E6A7B1D6EA62C0060F896 /* ThrowScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE2E6A7A1D6EA5FE0060F896 /* ThrowScope.cpp */; }; 2442 2443 FE3022D21E3D73A500BAC493 /* SigillCrashAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */; }; … … 5098 5099 FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; }; 5099 5100 FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; }; 5101 FE2A875F1F02381600EB31B2 /* MinimumReservedZoneSize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MinimumReservedZoneSize.h; sourceTree = "<group>"; }; 5100 5102 FE2E6A7A1D6EA5FE0060F896 /* ThrowScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThrowScope.cpp; sourceTree = "<group>"; }; 5101 5103 FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SigillCrashAnalyzer.cpp; sourceTree = "<group>"; }; … … 6942 6944 90213E3C123A40C200D422F3 /* MemoryStatistics.h */, 6943 6945 7C008CE5187631B600955C24 /* Microtask.h */, 6946 FE2A875F1F02381600EB31B2 /* MinimumReservedZoneSize.h */, 6944 6947 E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */, 6945 6948 E355F3511B7DC85300C50DC5 /* ModuleLoaderPrototype.h */, … … 8818 8821 0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */, 8819 8822 0F0332C618B53FA9005F979A /* FTLWeight.h in Headers */, 8823 FE2A87601F02381600EB31B2 /* MinimumReservedZoneSize.h in Headers */, 8820 8824 53C6FEEF1E8ADFA900B18425 /* WasmOpcodeOrigin.h in Headers */, 8821 8825 0F0332C818B546EC005F979A /* FTLWeightedTarget.h in Headers */, -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r218861 r218869 194 194 performGeneratorification(m_codeBlock.get(), m_instructions, m_generatorFrameSymbolTable.get(), m_generatorFrameSymbolTableIndex); 195 195 196 RELEASE_ASSERT(static_cast<unsigned>(m_codeBlock->numCalleeLocals()) < static_cast<unsigned>(FirstConstantRegisterIndex)); 196 197 m_codeBlock->setInstructions(std::make_unique<UnlinkedInstructionStream>(m_instructions)); 197 198 -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r217108 r218869 1 1 /* 2 * Copyright (C) 2011 , 2013-2016Apple Inc. All rights reserved.2 * Copyright (C) 2011-2017 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 1151 1151 unsigned Graph::requiredRegisterCountForExecutionAndExit() 1152 1152 { 1153 // FIXME: We should make sure that frameRegisterCount() and requiredRegisterCountForExit() 1154 // never overflows. https://bugs.webkit.org/show_bug.cgi?id=173852 1153 1155 return std::max(frameRegisterCount(), requiredRegisterCountForExit()); 1154 1156 } -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r218794 r218869 1 1 /* 2 * Copyright (C) 2011 , 2013-2016Apple Inc. All rights reserved.2 * Copyright (C) 2011-2017 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 355 355 } 356 356 357 static void emitStackOverflowCheck(JITCompiler& jit, MacroAssembler::JumpList& stackOverflow) 358 { 359 int frameTopOffset = virtualRegisterForLocal(jit.graph().requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register); 360 unsigned maxFrameSize = -frameTopOffset; 361 362 jit.addPtr(MacroAssembler::TrustedImm32(frameTopOffset), GPRInfo::callFrameRegister, GPRInfo::regT1); 363 if (UNLIKELY(maxFrameSize > Options::reservedZoneSize())) 364 stackOverflow.append(jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, GPRInfo::callFrameRegister)); 365 stackOverflow.append(jit.branchPtr(MacroAssembler::Above, MacroAssembler::AbsoluteAddress(jit.vm()->addressOfSoftStackLimit()), GPRInfo::regT1)); 366 } 367 357 368 void JITCompiler::compile() 358 369 { … … 362 373 363 374 // Plant a check that sufficient space is available in the JSStack. 364 addPtr(TrustedImm32(virtualRegisterForLocal(m_graph.requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);365 Jump stackOverflow = branchPtr(Above, AbsoluteAddress(vm()->addressOfSoftStackLimit()), GPRInfo::regT1);375 JumpList stackOverflow; 376 emitStackOverflowCheck(*this, stackOverflow); 366 377 367 378 addPtr(TrustedImm32(m_graph.stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, stackPointerRegister); … … 425 436 Label fromArityCheck(this); 426 437 // Plant a check that sufficient space is available in the JSStack. 427 addPtr(TrustedImm32(virtualRegisterForLocal(m_graph.requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);428 Jump stackOverflow = branchPtr(Above, AbsoluteAddress(vm()->addressOfSoftStackLimit()), GPRInfo::regT1);438 JumpList stackOverflow; 439 emitStackOverflowCheck(*this, stackOverflow); 429 440 430 441 // Move the stack pointer down to accommodate locals -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r218794 r218869 215 215 216 216 unsigned ftlFrameSize = params.proc().frameSize(); 217 218 jit.addPtr(MacroAssembler::TrustedImm32(-std::max(exitFrameSize, ftlFrameSize)), fp, scratch); 219 MacroAssembler::Jump stackOverflow = jit.branchPtr(MacroAssembler::Above, addressOfStackLimit, scratch); 217 unsigned maxFrameSize = std::max(exitFrameSize, ftlFrameSize); 218 219 jit.addPtr(MacroAssembler::TrustedImm32(-maxFrameSize), fp, scratch); 220 MacroAssembler::JumpList stackOverflow; 221 if (UNLIKELY(maxFrameSize > Options::reservedZoneSize())) 222 stackOverflow.append(jit.branchPtr(MacroAssembler::Above, scratch, fp)); 223 stackOverflow.append(jit.branchPtr(MacroAssembler::Above, addressOfStackLimit, scratch)); 220 224 221 225 params.addLatePath([=] (CCallHelpers& jit) { -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r218794 r218869 662 662 } 663 663 664 addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, regT1); 665 Jump stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfSoftStackLimit()), regT1); 664 int frameTopOffset = stackPointerOffsetFor(m_codeBlock) * sizeof(Register); 665 unsigned maxFrameSize = -frameTopOffset; 666 addPtr(TrustedImm32(frameTopOffset), callFrameRegister, regT1); 667 JumpList stackOverflow; 668 if (UNLIKELY(maxFrameSize > Options::reservedZoneSize())) 669 stackOverflow.append(branchPtr(Above, regT1, callFrameRegister)); 670 stackOverflow.append(branchPtr(Above, AbsoluteAddress(m_vm->addressOfSoftStackLimit()), regT1)); 666 671 667 672 move(regT1, stackPointerRegister); -
trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.cpp
r214531 r218869 1 1 /* 2 * Copyright (C) 2015-201 6Apple Inc. All rights reserved.2 * Copyright (C) 2015-2017 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 83 83 emitSetVarargsFrame(jit, scratchGPR1, true, numUsedSlotsGPR, scratchGPR2); 84 84 85 slowCase.append(jit.branchPtr(CCallHelpers::Above, scratchGPR2, GPRInfo::callFrameRegister)); 85 86 slowCase.append(jit.branchPtr(CCallHelpers::Above, CCallHelpers::AbsoluteAddress(vm.addressOfSoftStackLimit()), scratchGPR2)); 86 87 -
trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
r218868 r218869 511 511 // throw the StackOverflowError unconditionally. 512 512 #if !ENABLE(JIT) 513 ASSERT(!vm.interpreter->cloopStack().containsAddress(exec->topOfFrame())); 514 if (LIKELY(vm.ensureStackCapacityFor(exec->topOfFrame()))) 515 LLINT_RETURN_TWO(pc, 0); 513 Register* topOfFrame = exec->topOfFrame(); 514 if (LIKELY(topOfFrame < exec)) { 515 ASSERT(!vm.interpreter->cloopStack().containsAddress(topOfFrame)); 516 if (LIKELY(vm.ensureStackCapacityFor(topOfFrame))) 517 LLINT_RETURN_TWO(pc, 0); 518 } 516 519 #endif 517 520 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r217840 r218869 995 995 getFrameRegisterSizeForCodeBlock(t1, t0) 996 996 subp cfr, t0, t0 997 bpa t0, cfr, .needStackCheck 997 998 loadp CodeBlock::m_vm[t1], t2 998 999 if C_LOOP … … 1002 1003 end 1003 1004 1005 .needStackCheck: 1004 1006 # Stack height check failed - need to call a slow_path. 1005 1007 # Set up temporary stack pointer for call including callee saves -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r213107 r218869 149 149 lshiftp 3, t4 150 150 subp sp, t4, t3 151 bpa t3, sp, .throwStackOverflow 151 152 152 153 # Ensure that we have enough additional stack capacity for the incoming args, … … 173 174 end 174 175 176 .throwStackOverflow: 175 177 subp 8, sp # Align stack for cCall2() to make a call. 176 178 move vm, a0 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r213107 r218869 137 137 lshiftp 3, t4 138 138 subp sp, t4, t3 139 bpa t3, sp, .throwStackOverflow 139 140 140 141 # Ensure that we have enough additional stack capacity for the incoming args, … … 161 162 end 162 163 164 .throwStackOverflow: 163 165 move vm, a0 164 166 move protoCallFrame, a1 -
trunk/Source/JavaScriptCore/runtime/Options.cpp
r217993 r218869 30 30 #include "LLIntCommon.h" 31 31 #include "LLIntData.h" 32 #include "MinimumReservedZoneSize.h" 32 33 #include "SigillCrashAnalyzer.h" 33 34 #include <algorithm> … … 497 498 if (Options::useSigillCrashAnalyzer()) 498 499 enableSigillCrashAnalyzer(); 500 501 if (Options::reservedZoneSize() < minimumReservedZoneSize) 502 Options::reservedZoneSize() = minimumReservedZoneSize; 503 if (Options::softReservedZoneSize() < Options::reservedZoneSize() + minimumReservedZoneSize) 504 Options::softReservedZoneSize() = Options::reservedZoneSize() + minimumReservedZoneSize; 499 505 } 500 506 -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r218794 r218869 79 79 #include "Lexer.h" 80 80 #include "Lookup.h" 81 #include "MinimumReservedZoneSize.h" 81 82 #include "ModuleProgramCodeBlock.h" 82 83 #include "NativeStdFunctionCell.h" … … 671 672 #endif 672 673 674 const StackBounds& stack = wtfThreadData().stack(); 673 675 size_t reservedZoneSize = Options::reservedZoneSize(); 676 // We should have already ensured that Options::reservedZoneSize() >= minimumReserveZoneSize at 677 // options initialization time, and the option value should not have been changed thereafter. 678 // We don't have the ability to assert here that it hasn't changed, but we can at least assert 679 // that the value is sane. 680 RELEASE_ASSERT(reservedZoneSize >= minimumReservedZoneSize); 681 674 682 if (m_stackPointerAtVMEntry) { 675 ASSERT( wtfThreadData().stack().isGrowingDownward());683 ASSERT(stack.isGrowingDownward()); 676 684 char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry); 677 m_softStackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_currentSoftReservedZoneSize);678 m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), reservedZoneSize);685 m_softStackLimit = stack.recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_currentSoftReservedZoneSize); 686 m_stackLimit = stack.recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), reservedZoneSize); 679 687 } else { 680 m_softStackLimit = wtfThreadData().stack().recursionLimit(m_currentSoftReservedZoneSize);681 m_stackLimit = wtfThreadData().stack().recursionLimit(reservedZoneSize);688 m_softStackLimit = stack.recursionLimit(m_currentSoftReservedZoneSize); 689 m_stackLimit = stack.recursionLimit(reservedZoneSize); 682 690 } 683 691 -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r218216 r218869 417 417 )); 418 418 const int32_t checkSize = m_makesCalls ? (wasmFrameSize + extraFrameSize).unsafeGet() : wasmFrameSize.unsafeGet(); 419 bool needUnderflowCheck = static_cast<unsigned>(checkSize) > Options::reservedZoneSize(); 419 420 // This allows leaf functions to not do stack checks if their frame size is within 420 421 // certain limits since their caller would have already done the check. 421 if (m_makesCalls || wasmFrameSize >= minimumParentCheckSize ) {422 if (m_makesCalls || wasmFrameSize >= minimumParentCheckSize || needUnderflowCheck) { 422 423 jit.loadPtr(CCallHelpers::Address(context, Context::offsetOfCachedStackLimit()), scratch2); 423 424 jit.addPtr(CCallHelpers::TrustedImm32(-checkSize), fp, scratch1); 424 auto overflow = jit.branchPtr(CCallHelpers::Below, scratch1, scratch2); 425 MacroAssembler::JumpList overflow; 426 if (UNLIKELY(needUnderflowCheck)) 427 overflow.append(jit.branchPtr(CCallHelpers::Above, scratch1, fp)); 428 overflow.append(jit.branchPtr(CCallHelpers::Below, scratch1, scratch2)); 425 429 jit.addLinkTask([overflow] (LinkBuffer& linkBuffer) { 426 430 linkBuffer.link(overflow, CodeLocationLabel(Thunks::singleton().stub(throwStackOverflowFromWasmThunkGenerator).code())); -
trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
r217645 r218869 135 135 const intptr_t frameSize = (boxedArgs.size() + CallFrame::headerSizeInRegisters) * sizeof(Register); 136 136 const intptr_t stackSpaceUsed = 2 * frameSize; // We're making two calls. One to the wrapper, and one to the actual wasm code. 137 if (UNLIKELY((sp - stackSpaceUsed) < bitwise_cast<intptr_t>(vm.softStackLimit())))137 if (UNLIKELY((sp < stackSpaceUsed) || ((sp - stackSpaceUsed) < bitwise_cast<intptr_t>(vm.softStackLimit())))) 138 138 return JSValue::encode(throwException(exec, scope, createStackOverflowError(exec))); 139 139 }
Note: See TracChangeset
for help on using the changeset viewer.