Changeset 201495 in webkit
- Timestamp:
- May 29, 2016, 12:01:36 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 9 edited
-
CMakeLists.txt (modified) (1 diff)
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (1 diff)
-
interpreter/Interpreter.cpp (modified) (2 diffs)
-
runtime/InternalFunction.cpp (modified) (1 diff)
-
runtime/JSArray.h (modified) (1 diff)
-
runtime/ObjectPrototype.cpp (modified) (1 diff)
-
runtime/ProxyObject.cpp (modified) (16 diffs)
-
runtime/ProxyObject.h (modified) (2 diffs)
-
tests/stress/proxy-stack-overflow-exceptions.js (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/CMakeLists.txt
r201481 r201495 846 846 ) 847 847 848 # Extra flags for compile sources can go here. 849 set_source_files_properties(runtime/ProxyObject.cpp PROPERTIES COMPILE_FLAGS -fno-optimize-sibling-calls) 850 848 851 set(JavaScriptCore_OBJECT_LUT_SOURCES 849 852 runtime/ArrayConstructor.cpp -
trunk/Source/JavaScriptCore/ChangeLog
r201494 r201495 1 2016-05-29 Saam barati <sbarati@apple.com> 2 3 Stack overflow crashes with deep or cyclic proxy prototype chains 4 https://bugs.webkit.org/show_bug.cgi?id=157087 5 6 Reviewed by Filip Pizlo and Mark Lam. 7 8 Because a Proxy can call back into the JS runtime in arbitrary 9 ways, we may have effectively cyclic prototype chains and property lookups 10 by using a Proxy. We may also have arbitrarily long Proxy chains 11 where we call into a C frame for each link in the Proxy chain. 12 This means that every Proxy hook must be aware that it can stack overflow. 13 Before, only certain hooks were aware of this fact. That was a bug, 14 all hooks must assume they can stack overflow. 15 16 Also, because we may have effectively cyclic prototype chains, we 17 compile ProxyObject.cpp with -fno-optimize-sibling-calls. This prevents 18 tail call optimization from happening on any of the calls from 19 ProxyObject.cpp. We do this because we rely on the machine stack 20 growing for throwing a stack overflow error. It's better for developers 21 to be able to see a stack overflow error than to have their program 22 infinite loop because the compiler performed TCO. 23 24 This patch also fixes a couple call sites of various methods 25 where we didn't check for an exception. 26 27 * CMakeLists.txt: 28 * JavaScriptCore.xcodeproj/project.pbxproj: 29 * interpreter/Interpreter.cpp: 30 (JSC::sizeOfVarargs): 31 * runtime/InternalFunction.cpp: 32 (JSC::InternalFunction::createSubclassStructure): 33 * runtime/JSArray.h: 34 (JSC::getLength): 35 * runtime/ObjectPrototype.cpp: 36 (JSC::objectProtoFuncToString): 37 * runtime/ProxyObject.cpp: 38 (JSC::performProxyGet): 39 (JSC::ProxyObject::performInternalMethodGetOwnProperty): 40 (JSC::ProxyObject::performHasProperty): 41 (JSC::ProxyObject::getOwnPropertySlotCommon): 42 (JSC::ProxyObject::performPut): 43 (JSC::performProxyCall): 44 (JSC::performProxyConstruct): 45 (JSC::ProxyObject::performDelete): 46 (JSC::ProxyObject::performPreventExtensions): 47 (JSC::ProxyObject::performIsExtensible): 48 (JSC::ProxyObject::performDefineOwnProperty): 49 (JSC::ProxyObject::performGetOwnPropertyNames): 50 (JSC::ProxyObject::getOwnPropertyNames): 51 (JSC::ProxyObject::getPropertyNames): 52 (JSC::ProxyObject::getOwnNonIndexPropertyNames): 53 (JSC::ProxyObject::performSetPrototype): 54 (JSC::ProxyObject::performGetPrototype): 55 * runtime/ProxyObject.h: 56 (JSC::ProxyObject::create): 57 * tests/stress/proxy-stack-overflow-exceptions.js: Added. 58 (shouldThrowStackOverflow): 59 (const.emptyFunction): 60 (makeLongProxyChain): 61 (shouldThrowStackOverflow.longProxyChain): 62 (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain1): 63 (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain2): 64 (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain3): 65 (shouldThrowStackOverflow.longProxyChainBind): 66 (shouldThrowStackOverflow.longProxyChainPropertyAccess): 67 (shouldThrowStackOverflow.longProxyChainReflectConstruct): 68 (shouldThrowStackOverflow.longProxyChainReflectSet): 69 (shouldThrowStackOverflow.longProxyChainReflectOwnKeys): 70 (shouldThrowStackOverflow.longProxyChainGetPrototypeOf): 71 (shouldThrowStackOverflow.longProxyChainSetPrototypeOf): 72 (shouldThrowStackOverflow.longProxyChainGetOwnPropertyDescriptor): 73 (shouldThrowStackOverflow.longProxyChainDefineProperty): 74 (shouldThrowStackOverflow.longProxyChainIsExtensible): 75 (shouldThrowStackOverflow.longProxyChainPreventExtensions): 76 (shouldThrowStackOverflow.longProxyChainDeleteProperty): 77 (shouldThrowStackOverflow.longProxyChainWithScope): 78 (shouldThrowStackOverflow.longProxyChainWithScope2): 79 (shouldThrowStackOverflow.longProxyChainWithScope3): 80 (shouldThrowStackOverflow.longProxyChainArrayPrototypePush): 81 (shouldThrowStackOverflow.longProxyChainWithScope4): 82 (shouldThrowStackOverflow.longProxyChainCall): 83 (shouldThrowStackOverflow.longProxyChainConstruct): 84 (shouldThrowStackOverflow.longProxyChainHas): 85 1 86 2016-05-28 Andreas Kling <akling@apple.com> 2 87 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r201481 r201495 1289 1289 79B00CBC1C6AB07E0088C65D /* ProxyConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CB81C6AB07E0088C65D /* ProxyConstructor.cpp */; }; 1290 1290 79B00CBD1C6AB07E0088C65D /* ProxyConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B00CB91C6AB07E0088C65D /* ProxyConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1291 79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */; };1291 79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */; settings = {COMPILER_FLAGS = "-fno-optimize-sibling-calls"; }; }; 1292 1292 79B00CBF1C6AB07E0088C65D /* ProxyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B00CBB1C6AB07E0088C65D /* ProxyObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1293 1293 79C4B15D1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */; }; -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r201445 r201495 219 219 break; 220 220 case ScopedArgumentsType: 221 length = jsCast<ScopedArguments*>(cell)->length(callFrame);221 length = jsCast<ScopedArguments*>(cell)->length(callFrame); 222 222 break; 223 223 case StringType: … … 227 227 ASSERT(arguments.isObject()); 228 228 length = getLength(callFrame, jsCast<JSObject*>(cell)); 229 if (UNLIKELY(callFrame->hadException())) 230 return 0; 229 231 break; 230 232 } 233 231 234 232 235 if (length >= firstVarArgOffset) -
trunk/Source/JavaScriptCore/runtime/InternalFunction.cpp
r200430 r201495 110 110 111 111 // Note, Reflect.construct might cause the profile to churn but we don't care. 112 JS Object* prototype = jsDynamicCast<JSObject*>(newTarget.get(exec, exec->propertyNames().prototype));113 if ( exec->hadException())112 JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype); 113 if (UNLIKELY(vm.exception())) 114 114 return nullptr; 115 if ( prototype)115 if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue)) 116 116 return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass); 117 117 } else { 118 JS Object* prototype = jsDynamicCast<JSObject*>(newTarget.get(exec, exec->propertyNames().prototype));119 if ( exec->hadException())118 JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype); 119 if (UNLIKELY(vm.exception())) 120 120 return nullptr; 121 if ( prototype) {121 if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue)) { 122 122 // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target. 123 123 // Thus, we don't care about the cost of looking up the structure from our hash table every time. -
trunk/Source/JavaScriptCore/runtime/JSArray.h
r201049 r201495 353 353 if (isJSArray(obj)) 354 354 return jsCast<JSArray*>(obj)->length(); 355 return obj->get(exec, exec->propertyNames().length).toUInt32(exec); 355 356 VM& vm = exec->vm(); 357 JSValue lengthValue = obj->get(exec, vm.propertyNames->length); 358 if (UNLIKELY(vm.exception())) 359 return UINT_MAX; 360 return lengthValue.toUInt32(exec); 356 361 } 357 362 -
trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
r197794 r201495 283 283 if (thisObject->getPropertySlot(exec, toStringTagSymbol, toStringTagSlot)) { 284 284 JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol); 285 if (UNLIKELY(vm.exception())) 286 return JSValue::encode(JSValue()); 285 287 if (stringTag.isString()) { 286 288 JSRopeString::RopeBuilder ropeBuilder(vm); -
trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp
r201322 r201495 35 35 #include "StructureInlines.h" 36 36 37 // Note that this file is compile with -fno-optimize-sibling-calls because we rely on the machine stack 38 // growing larger for throwing OOM errors for when we have an effectively cyclic prototype chain. 39 37 40 namespace JSC { 38 41 … … 96 99 { 97 100 VM& vm = exec->vm(); 98 if ( !vm.isSafeToRecurse()) {101 if (UNLIKELY(!vm.isSafeToRecurse())) { 99 102 throwStackOverflowError(exec); 100 103 return JSValue::encode(JSValue()); … … 156 159 { 157 160 VM& vm = exec->vm(); 161 if (UNLIKELY(!vm.isSafeToRecurse())) { 162 throwStackOverflowError(exec); 163 return false; 164 } 158 165 JSObject* target = this->target(); 159 166 … … 258 265 { 259 266 VM& vm = exec->vm(); 267 if (UNLIKELY(!vm.isSafeToRecurse())) { 268 throwStackOverflowError(exec); 269 return false; 270 } 260 271 JSObject* target = this->target(); 261 272 slot.setValue(this, None, jsUndefined()); // Nobody should rely on our value, but be safe and protect against any bad actors reading our value. … … 319 330 bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot& slot) 320 331 { 332 if (UNLIKELY(!exec->vm().isSafeToRecurse())) { 333 throwStackOverflowError(exec); 334 return false; 335 } 321 336 slot.disableCaching(); 322 337 slot.setIsTaintedByProxy(); … … 354 369 { 355 370 VM& vm = exec->vm(); 356 if ( !vm.isSafeToRecurse()) {371 if (UNLIKELY(!vm.isSafeToRecurse())) { 357 372 throwStackOverflowError(exec); 358 373 return false; … … 446 461 { 447 462 VM& vm = exec->vm(); 463 if (UNLIKELY(!vm.isSafeToRecurse())) { 464 throwStackOverflowError(exec); 465 return JSValue::encode(JSValue()); 466 } 448 467 ProxyObject* proxy = jsCast<ProxyObject*>(exec->callee()); 449 468 JSValue handlerValue = proxy->handler(); … … 491 510 { 492 511 VM& vm = exec->vm(); 512 if (UNLIKELY(!vm.isSafeToRecurse())) { 513 throwStackOverflowError(exec); 514 return JSValue::encode(JSValue()); 515 } 493 516 ProxyObject* proxy = jsCast<ProxyObject*>(exec->callee()); 494 517 JSValue handlerValue = proxy->handler(); … … 542 565 { 543 566 VM& vm = exec->vm(); 567 if (UNLIKELY(!vm.isSafeToRecurse())) { 568 throwStackOverflowError(exec); 569 return false; 570 } 544 571 545 572 if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid()))) … … 614 641 { 615 642 VM& vm = exec->vm(); 643 if (UNLIKELY(!vm.isSafeToRecurse())) { 644 throwStackOverflowError(exec); 645 return false; 646 } 616 647 617 648 JSValue handlerValue = this->handler(); … … 662 693 { 663 694 VM& vm = exec->vm(); 695 if (UNLIKELY(!vm.isSafeToRecurse())) { 696 throwStackOverflowError(exec); 697 return false; 698 } 664 699 665 700 JSValue handlerValue = this->handler(); … … 716 751 { 717 752 VM& vm = exec->vm(); 753 if (UNLIKELY(!vm.isSafeToRecurse())) { 754 throwStackOverflowError(exec); 755 return false; 756 } 718 757 719 758 JSObject* target = this->target(); … … 809 848 { 810 849 VM& vm = exec->vm(); 850 if (UNLIKELY(!vm.isSafeToRecurse())) { 851 throwStackOverflowError(exec); 852 return; 853 } 811 854 JSValue handlerValue = this->handler(); 812 855 if (handlerValue.isNull()) { … … 948 991 } 949 992 993 void ProxyObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNameArray, EnumerationMode enumerationMode) 994 { 995 JSObject::getPropertyNames(object, exec, propertyNameArray, enumerationMode); 996 } 997 950 998 void ProxyObject::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) 951 999 { … … 969 1017 970 1018 VM& vm = exec->vm(); 1019 if (UNLIKELY(!vm.isSafeToRecurse())) { 1020 throwStackOverflowError(exec); 1021 return false; 1022 } 971 1023 972 1024 JSValue handlerValue = this->handler(); … … 1029 1081 { 1030 1082 VM& vm = exec->vm(); 1083 if (UNLIKELY(!vm.isSafeToRecurse())) { 1084 throwStackOverflowError(exec); 1085 return JSValue(); 1086 } 1031 1087 1032 1088 JSValue handlerValue = this->handler(); -
trunk/Source/JavaScriptCore/runtime/ProxyObject.h
r198023 r201495 37 37 typedef JSNonFinalObject Base; 38 38 39 // We lie an say we override getPropertyNames() because it prevents40 // property name enumeration caching.41 39 const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | ProhibitsPropertyCaching; 42 40 … … 88 86 static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); 89 87 static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 88 static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 90 89 static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 91 90 static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
Note:
See TracChangeset
for help on using the changeset viewer.