Changeset 252239 in webkit
- Timestamp:
- Nov 8, 2019 8:58:49 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r252196 r252239 1 2019-11-07 Mark Lam <mark.lam@apple.com> 2 3 Add a stack overflow check in Yarr::ByteCompiler::emitDisjunction(). 4 https://bugs.webkit.org/show_bug.cgi?id=203936 5 <rdar://problem/56624724> 6 7 Reviewed by Saam Barati. 8 9 This issue originally manifested as incorrect-exception-assertion-in-operationRegExpExecNonGlobalOrSticky.js 10 failing on iOS devices due to its smaller stack. We adapted the original test 11 here using $vm.callWithStackSize() to reproduce the issue on x86_64 though it 12 has a much larger physical stack to work with. This new test will crash while 13 stepping on the guard page beyond the end of the stack if the fix is not applied. 14 15 * stress/stack-overflow-in-yarr-byteCompile.js: Added. 16 1 17 2019-11-07 Tuomas Karkkainen <tuomas.webkit@apple.com> 2 18 -
trunk/Source/JavaScriptCore/ChangeLog
r252231 r252239 1 2019-11-07 Mark Lam <mark.lam@apple.com> 2 3 Add a stack overflow check in Yarr::ByteCompiler::emitDisjunction(). 4 https://bugs.webkit.org/show_bug.cgi?id=203936 5 <rdar://problem/56624724> 6 7 Reviewed by Saam Barati. 8 9 Basically, any functions below Yarr::ByteCompiler::compile() that recurses need 10 to check if it's safe to recurse before doing so. This patch adds the stack 11 checks in Yarr::ByteCompiler::compile() because it is the entry point to this 12 sub-system, and Yarr::ByteCompiler::emitDisjunction() because it is the only 13 function that recurses. All other functions called below compile() are either 14 leaf functions or have shallow stack usage. Hence, their stack needs are covered 15 by the DefaultReservedZone, and they do not need stack checks. 16 17 This patch also does the following: 18 1. Added $vm.callWithStackSize() which can be used to call a test function near 19 the end of the physical stack. This enables is to simulate the smaller stack 20 size of more resource constrained devices. 21 22 $vm.callWithStackSize() uses inline asm to adjust the stack pointer and 23 does the callback via the JIT probe trampoline. 24 25 2. Added the --disableOptionsFreezingForTesting to the jsc shell to make it 26 possible to disable freezing of JSC options. $vm.callWithStackSize() relies 27 on this to modify the VM's stack limits. 28 29 3. Removed the inline modifier on VM::updateStackLimits() so that we can call it 30 from $vm.callWithStackSize() as well. It is not a performance critical 31 function and is rarely called. 32 33 4. Added a JSDollarVMHelper class that other parts of the system can declare as 34 a friend. This gives $vm a backdoor into the private functions and fields of 35 classes for its debugging work. In this patch, we're only using it to access 36 VM::updateVMStackLimits(). 37 38 * jsc.cpp: 39 (CommandLine::parseArguments): 40 * runtime/VM.cpp: 41 (JSC::VM::updateStackLimits): 42 * runtime/VM.h: 43 * tools/JSDollarVM.cpp: 44 (JSC::JSDollarVMHelper::JSDollarVMHelper): 45 (JSC::JSDollarVMHelper::vmStackStart): 46 (JSC::JSDollarVMHelper::vmStackLimit): 47 (JSC::JSDollarVMHelper::vmSoftStackLimit): 48 (JSC::JSDollarVMHelper::updateVMStackLimits): 49 (JSC::callWithStackSizeProbeFunction): 50 (JSC::functionCallWithStackSize): 51 (JSC::JSDollarVM::finishCreation): 52 (IGNORE_WARNINGS_BEGIN): Deleted. 53 * yarr/YarrInterpreter.cpp: 54 (JSC::Yarr::ByteCompiler::compile): 55 (JSC::Yarr::ByteCompiler::emitDisjunction): 56 (JSC::Yarr::ByteCompiler::isSafeToRecurse): 57 1 58 2019-11-07 Tadeu Zagallo <tzagallo@apple.com> 2 59 -
trunk/Source/JavaScriptCore/jsc.cpp
r251691 r252239 2892 2892 continue; 2893 2893 } 2894 if (!strcmp(arg, "--disableOptionsFreezingForTesting")) { 2895 Config::disableFreezingForTesting(); 2896 continue; 2897 } 2894 2898 2895 2899 static const char* timeoutMultiplierOptStr = "--timeoutMultiplier="; -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r252177 r252239 882 882 #endif 883 883 884 inlinevoid VM::updateStackLimits()884 void VM::updateStackLimits() 885 885 { 886 886 #if OS(WINDOWS) -
trunk/Source/JavaScriptCore/runtime/VM.h
r252177 r252239 1094 1094 friend class CatchScope; 1095 1095 friend class ExceptionScope; 1096 friend class JSDollarVMHelper; 1096 1097 friend class ThrowScope; 1097 1098 friend class VMTraps; -
trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp
r251736 r252239 32 32 #include "DOMJITGetterSetter.h" 33 33 #include "Debugger.h" 34 #include "Error.h" 34 35 #include "FrameTracers.h" 35 36 #include "FunctionCodeBlock.h" … … 44 45 #include "Options.h" 45 46 #include "Parser.h" 47 #include "ProbeContext.h" 46 48 #include "ShadowChicken.h" 47 49 #include "Snippet.h" … … 64 66 65 67 IGNORE_WARNINGS_BEGIN("frame-address") 68 69 extern "C" void ctiMasmProbeTrampoline(); 70 71 namespace JSC { 72 73 // This class is only here as a simple way to grant JSDollarVM friend privileges 74 // to all the classes that it needs special access to. 75 class JSDollarVMHelper { 76 public: 77 JSDollarVMHelper(VM& vm) 78 : m_vm(vm) 79 { } 80 81 void updateVMStackLimits() { return m_vm.updateStackLimits(); }; 82 83 private: 84 VM& m_vm; 85 }; 86 87 } // namespace JSC 66 88 67 89 namespace { … … 1969 1991 } 1970 1992 1993 // Calls the specified test function after adjusting the stack to have the specified 1994 // remaining size from the end of the physical stack. 1995 // Usage: $vm.callWithStackSize(funcToCall, desiredStackSize) 1996 // 1997 // This function will only work in test configurations, specifically, only if JSC 1998 // options are not frozen. For the jsc shell, the --disableOptionsFreezingForTesting 1999 // argument needs to be passed in on the command line. 2000 2001 #if ENABLE(MASM_PROBE) 2002 static void callWithStackSizeProbeFunction(Probe::State* state) 2003 { 2004 JSGlobalObject* globalObject = bitwise_cast<JSGlobalObject*>(state->arg); 2005 JSFunction* function = bitwise_cast<JSFunction*>(state->probeFunction); 2006 state->initializeStackFunction = nullptr; 2007 state->initializeStackArg = nullptr; 2008 2009 DollarVMAssertScope assertScope; 2010 VM& vm = globalObject->vm(); 2011 2012 CallData callData; 2013 CallType callType = getCallData(vm, function, callData); 2014 MarkedArgumentBuffer args; 2015 call(globalObject, function, callType, callData, jsUndefined(), args); 2016 } 2017 #endif // ENABLE(MASM_PROBE) 2018 2019 static EncodedJSValue JSC_HOST_CALL functionCallWithStackSize(JSGlobalObject* globalObject, CallFrame* callFrame) 2020 { 2021 DollarVMAssertScope assertScope; 2022 VM& vm = globalObject->vm(); 2023 JSLockHolder lock(vm); 2024 auto throwScope = DECLARE_THROW_SCOPE(vm); 2025 2026 #if OS(DARWIN) && CPU(X86_64) 2027 constexpr bool isSupportedByPlatform = true; 2028 #else 2029 constexpr bool isSupportedByPlatform = false; 2030 #endif 2031 2032 if (!isSupportedByPlatform) 2033 return throwVMError(globalObject, throwScope, "Not supported for this platform"); 2034 2035 #if ENABLE(MASM_PROBE) 2036 if (g_jscConfig.isPermanentlyFrozen || !g_jscConfig.disabledFreezingForTesting) 2037 return throwVMError(globalObject, throwScope, "Options are frozen"); 2038 2039 if (callFrame->argumentCount() < 2) 2040 return throwVMError(globalObject, throwScope, "Invalid number of arguments"); 2041 JSValue arg0 = callFrame->argument(0); 2042 JSValue arg1 = callFrame->argument(1); 2043 if (!arg0.isFunction(vm)) 2044 return throwVMError(globalObject, throwScope, "arg0 should be a function"); 2045 if (!arg1.isNumber()) 2046 return throwVMError(globalObject, throwScope, "arg1 should be a number"); 2047 2048 JSFunction* function = jsCast<JSFunction*>(arg0.toObject(globalObject)); 2049 size_t desiredStackSize = arg1.asNumber(); 2050 2051 const StackBounds& bounds = Thread::current().stack(); 2052 uint8_t* currentStackPosition = bitwise_cast<uint8_t*>(currentStackPointer()); 2053 uint8_t* end = bitwise_cast<uint8_t*>(bounds.end()); 2054 uint8_t* desiredStart = end + desiredStackSize; 2055 if (desiredStart >= currentStackPosition) 2056 return throwVMError(globalObject, throwScope, "Unable to setup desired stack size"); 2057 2058 JSDollarVMHelper helper(vm); 2059 2060 unsigned originalMaxPerThreadStackUsage = Options::maxPerThreadStackUsage(); 2061 void* originalVMSoftStackLimit = vm.softStackLimit(); 2062 void* originalVMStackLimit = vm.stackLimit(); 2063 2064 // This is a hack to make the VM think it's stack limits are near the end 2065 // of the physical stack. 2066 uint8_t* vmStackStart = bitwise_cast<uint8_t*>(vm.stackPointerAtVMEntry()); 2067 uint8_t* vmStackEnd = vmStackStart - originalMaxPerThreadStackUsage; 2068 ptrdiff_t sizeDiff = vmStackEnd - end; 2069 RELEASE_ASSERT(sizeDiff >= 0); 2070 RELEASE_ASSERT(sizeDiff < UINT_MAX); 2071 2072 Options::maxPerThreadStackUsage() = originalMaxPerThreadStackUsage + sizeDiff; 2073 helper.updateVMStackLimits(); 2074 2075 #if OS(DARWIN) && CPU(X86_64) 2076 __asm__ volatile ( 2077 "subq %[sizeDiff], %%rsp" "\n" 2078 "pushq %%rax" "\n" 2079 "pushq %%rcx" "\n" 2080 "pushq %%rdx" "\n" 2081 "pushq %%rbx" "\n" 2082 "callq *%%rax" "\n" 2083 "addq %[sizeDiff], %%rsp" "\n" 2084 : 2085 : "a" (ctiMasmProbeTrampoline) 2086 , "c" (callWithStackSizeProbeFunction) 2087 , "d" (function) 2088 , "b" (globalObject) 2089 , [sizeDiff] "rm" (sizeDiff) 2090 : "memory" 2091 ); 2092 #else 2093 UNUSED_PARAM(function); 2094 UNUSED_PARAM(callWithStackSizeProbeFunction); 2095 #endif // OS(DARWIN) && CPU(X86_64) 2096 2097 Options::maxPerThreadStackUsage() = originalMaxPerThreadStackUsage; 2098 helper.updateVMStackLimits(); 2099 RELEASE_ASSERT(vm.softStackLimit() == originalVMSoftStackLimit); 2100 RELEASE_ASSERT(vm.stackLimit() == originalVMStackLimit); 2101 2102 return encodedJSUndefined(); 2103 2104 #else // not ENABLE(MASM_PROBE) 2105 UNUSED_PARAM(callFrame); 2106 return throwVMError(globalObject, throwScope, "Not supported for this platform"); 2107 #endif // ENABLE(MASM_PROBE) 2108 } 2109 1971 2110 // Creates a new global object. 1972 2111 // Usage: $vm.createGlobalObject() … … 2630 2769 addFunction(vm, "haveABadTime", functionHaveABadTime, 1); 2631 2770 addFunction(vm, "isHavingABadTime", functionIsHavingABadTime, 1); 2771 2772 addFunction(vm, "callWithStackSize", functionCallWithStackSize, 2); 2632 2773 2633 2774 addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0); -
trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp
r248846 r252239 35 35 #include <wtf/CheckedArithmetic.h> 36 36 #include <wtf/DataLog.h> 37 #include <wtf/StackCheck.h> 37 38 #include <wtf/text/CString.h> 38 39 #include <wtf/text/WTFString.h> … … 1695 1696 std::unique_ptr<BytecodePattern> compile(BumpPointerAllocator* allocator, ConcurrentJSLock* lock, ErrorCode& errorCode) 1696 1697 { 1698 if (UNLIKELY(!isSafeToRecurse())) { 1699 errorCode = ErrorCode::TooManyDisjunctions; 1700 return nullptr; 1701 } 1702 1697 1703 regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough()); 1698 1704 if (auto error = emitDisjunction(m_pattern.m_body, 0, 0)) { … … 2029 2035 Optional<ErrorCode> WARN_UNUSED_RETURN emitDisjunction(PatternDisjunction* disjunction, Checked<unsigned, RecordOverflow> inputCountAlreadyChecked, unsigned parenthesesInputCountAlreadyChecked) 2030 2036 { 2037 if (UNLIKELY(!isSafeToRecurse())) 2038 return ErrorCode::TooManyDisjunctions; 2039 2031 2040 for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { 2032 2041 auto currentCountAlreadyChecked = inputCountAlreadyChecked; … … 2406 2415 2407 2416 private: 2417 inline bool isSafeToRecurse() { return m_stackCheck.isSafeToRecurse(); } 2418 2408 2419 YarrPattern& m_pattern; 2409 2420 std::unique_ptr<ByteDisjunction> m_bodyDisjunction; 2421 StackCheck m_stackCheck; 2410 2422 unsigned m_currentAlternativeIndex { 0 }; 2411 2423 Vector<ParenthesesStackEntry> m_parenthesesStack; -
trunk/Source/WTF/ChangeLog
r252177 r252239 1 2019-11-07 Mark Lam <mark.lam@apple.com> 2 3 Add a stack overflow check in Yarr::ByteCompiler::emitDisjunction(). 4 https://bugs.webkit.org/show_bug.cgi?id=203936 5 <rdar://problem/56624724> 6 7 Reviewed by Saam Barati. 8 9 1. Add a StackCheck utility class so that we don't have to keep reinventing this 10 every time we need to add stack checking somewhere. 11 2. Rename some arguments and constants in StackBounds to be more descriptive of 12 what they actually are. 13 14 * WTF.xcodeproj/project.pbxproj: 15 * wtf/CMakeLists.txt: 16 * wtf/StackBounds.h: 17 (WTF::StackBounds::recursionLimit const): 18 * wtf/StackCheck.h: Added. 19 (WTF::StackCheck::StackCheck): 20 (WTF::StackCheck::isSafeToRecurse): 21 1 22 2019-11-06 Mark Lam <mark.lam@apple.com> 2 23 -
trunk/Source/WTF/WTF.xcodeproj/project.pbxproj
r252068 r252239 695 695 FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; }; 696 696 FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFAssertions.cpp; sourceTree = "<group>"; }; 697 FE1D6D87237401CD007A5C26 /* StackCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackCheck.h; sourceTree = "<group>"; }; 697 698 FE1E2C392240C05400F6B729 /* PtrTag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PtrTag.cpp; sourceTree = "<group>"; }; 698 699 FE1E2C41224187C600F6B729 /* PlatformRegisters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformRegisters.cpp; sourceTree = "<group>"; }; … … 1153 1154 A8A4730E151A825B004123FF /* StackBounds.cpp */, 1154 1155 A8A4730F151A825B004123FF /* StackBounds.h */, 1156 FE1D6D87237401CD007A5C26 /* StackCheck.h */, 1155 1157 FEEA4DF8216D7BE400AC0602 /* StackPointer.cpp */, 1156 1158 FEEA4DF7216D608C00AC0602 /* StackPointer.h */, -
trunk/Source/WTF/wtf/CMakeLists.txt
r252068 r252239 216 216 Spectrum.h 217 217 StackBounds.h 218 StackCheck.h 218 219 StackPointer.h 219 220 StackShot.h -
trunk/Source/WTF/wtf/StackBounds.h
r252177 r252239 35 35 class StackBounds { 36 36 WTF_MAKE_FAST_ALLOCATED; 37 public: 37 38 38 39 // This 64k number was picked because a sampling of stack usage differences … … 41 42 // conservative availability value that is not too large but comfortably 42 43 // exceeds 27k with some buffer for error. 43 static constexpr size_t s_defaultAvailabilityDelta= 64 * 1024;44 static constexpr size_t DefaultReservedZone = 64 * 1024; 44 45 45 public:46 46 static constexpr StackBounds emptyBounds() { return StackBounds(); } 47 47 … … 83 83 } 84 84 85 void* recursionLimit(size_t min AvailableDelta = s_defaultAvailabilityDelta) const85 void* recursionLimit(size_t minReservedZone = DefaultReservedZone) const 86 86 { 87 87 checkConsistency(); 88 return static_cast<char*>(m_bound) + min AvailableDelta;88 return static_cast<char*>(m_bound) + minReservedZone; 89 89 } 90 90
Note: See TracChangeset
for help on using the changeset viewer.