<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[201495] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/201495">201495</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-05-29 12:01:36 -0700 (Sun, 29 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Stack overflow crashes with deep or cyclic proxy prototype chains
https://bugs.webkit.org/show_bug.cgi?id=157087

Reviewed by Filip Pizlo and Mark Lam.

Because a Proxy can call back into the JS runtime in arbitrary
ways, we may have effectively cyclic prototype chains and property lookups
by using a Proxy. We may also have arbitrarily long Proxy chains
where we call into a C frame for each link in the Proxy chain.
This means that every Proxy hook must be aware that it can stack overflow.
Before, only certain hooks were aware of this fact. That was a bug,
all hooks must assume they can stack overflow.

Also, because we may have effectively cyclic prototype chains, we
compile ProxyObject.cpp with -fno-optimize-sibling-calls. This prevents
tail call optimization from happening on any of the calls from
ProxyObject.cpp. We do this because we rely on the machine stack
growing for throwing a stack overflow error. It's better for developers
to be able to see a stack overflow error than to have their program
infinite loop because the compiler performed TCO.

This patch also fixes a couple call sites of various methods
where we didn't check for an exception.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* interpreter/Interpreter.cpp:
(JSC::sizeOfVarargs):
* runtime/InternalFunction.cpp:
(JSC::InternalFunction::createSubclassStructure):
* runtime/JSArray.h:
(JSC::getLength):
* runtime/ObjectPrototype.cpp:
(JSC::objectProtoFuncToString):
* runtime/ProxyObject.cpp:
(JSC::performProxyGet):
(JSC::ProxyObject::performInternalMethodGetOwnProperty):
(JSC::ProxyObject::performHasProperty):
(JSC::ProxyObject::getOwnPropertySlotCommon):
(JSC::ProxyObject::performPut):
(JSC::performProxyCall):
(JSC::performProxyConstruct):
(JSC::ProxyObject::performDelete):
(JSC::ProxyObject::performPreventExtensions):
(JSC::ProxyObject::performIsExtensible):
(JSC::ProxyObject::performDefineOwnProperty):
(JSC::ProxyObject::performGetOwnPropertyNames):
(JSC::ProxyObject::getOwnPropertyNames):
(JSC::ProxyObject::getPropertyNames):
(JSC::ProxyObject::getOwnNonIndexPropertyNames):
(JSC::ProxyObject::performSetPrototype):
(JSC::ProxyObject::performGetPrototype):
* runtime/ProxyObject.h:
(JSC::ProxyObject::create):
* tests/stress/proxy-stack-overflow-exceptions.js: Added.
(shouldThrowStackOverflow):
(const.emptyFunction):
(makeLongProxyChain):
(shouldThrowStackOverflow.longProxyChain):
(shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain1):
(shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain2):
(shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain3):
(shouldThrowStackOverflow.longProxyChainBind):
(shouldThrowStackOverflow.longProxyChainPropertyAccess):
(shouldThrowStackOverflow.longProxyChainReflectConstruct):
(shouldThrowStackOverflow.longProxyChainReflectSet):
(shouldThrowStackOverflow.longProxyChainReflectOwnKeys):
(shouldThrowStackOverflow.longProxyChainGetPrototypeOf):
(shouldThrowStackOverflow.longProxyChainSetPrototypeOf):
(shouldThrowStackOverflow.longProxyChainGetOwnPropertyDescriptor):
(shouldThrowStackOverflow.longProxyChainDefineProperty):
(shouldThrowStackOverflow.longProxyChainIsExtensible):
(shouldThrowStackOverflow.longProxyChainPreventExtensions):
(shouldThrowStackOverflow.longProxyChainDeleteProperty):
(shouldThrowStackOverflow.longProxyChainWithScope):
(shouldThrowStackOverflow.longProxyChainWithScope2):
(shouldThrowStackOverflow.longProxyChainWithScope3):
(shouldThrowStackOverflow.longProxyChainArrayPrototypePush):
(shouldThrowStackOverflow.longProxyChainWithScope4):
(shouldThrowStackOverflow.longProxyChainCall):
(shouldThrowStackOverflow.longProxyChainConstruct):
(shouldThrowStackOverflow.longProxyChainHas):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeInternalFunctioncpp">trunk/Source/JavaScriptCore/runtime/InternalFunction.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayh">trunk/Source/JavaScriptCore/runtime/JSArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectPrototypecpp">trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeProxyObjectcpp">trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeProxyObjecth">trunk/Source/JavaScriptCore/runtime/ProxyObject.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressproxystackoverflowexceptionsjs">trunk/Source/JavaScriptCore/tests/stress/proxy-stack-overflow-exceptions.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -845,6 +845,9 @@
</span><span class="cx">     yarr/YarrSyntaxChecker.cpp
</span><span class="cx"> )
</span><span class="cx"> 
</span><ins>+# Extra flags for compile sources can go here.
+set_source_files_properties(runtime/ProxyObject.cpp PROPERTIES COMPILE_FLAGS -fno-optimize-sibling-calls)
+
</ins><span class="cx"> set(JavaScriptCore_OBJECT_LUT_SOURCES
</span><span class="cx">     runtime/ArrayConstructor.cpp
</span><span class="cx">     runtime/ArrayIteratorPrototype.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -1,3 +1,88 @@
</span><ins>+2016-05-29  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Stack overflow crashes with deep or cyclic proxy prototype chains
+        https://bugs.webkit.org/show_bug.cgi?id=157087
+
+        Reviewed by Filip Pizlo and Mark Lam.
+
+        Because a Proxy can call back into the JS runtime in arbitrary
+        ways, we may have effectively cyclic prototype chains and property lookups
+        by using a Proxy. We may also have arbitrarily long Proxy chains
+        where we call into a C frame for each link in the Proxy chain.
+        This means that every Proxy hook must be aware that it can stack overflow.
+        Before, only certain hooks were aware of this fact. That was a bug,
+        all hooks must assume they can stack overflow.
+
+        Also, because we may have effectively cyclic prototype chains, we
+        compile ProxyObject.cpp with -fno-optimize-sibling-calls. This prevents
+        tail call optimization from happening on any of the calls from
+        ProxyObject.cpp. We do this because we rely on the machine stack
+        growing for throwing a stack overflow error. It's better for developers
+        to be able to see a stack overflow error than to have their program
+        infinite loop because the compiler performed TCO.
+
+        This patch also fixes a couple call sites of various methods
+        where we didn't check for an exception.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * interpreter/Interpreter.cpp:
+        (JSC::sizeOfVarargs):
+        * runtime/InternalFunction.cpp:
+        (JSC::InternalFunction::createSubclassStructure):
+        * runtime/JSArray.h:
+        (JSC::getLength):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::objectProtoFuncToString):
+        * runtime/ProxyObject.cpp:
+        (JSC::performProxyGet):
+        (JSC::ProxyObject::performInternalMethodGetOwnProperty):
+        (JSC::ProxyObject::performHasProperty):
+        (JSC::ProxyObject::getOwnPropertySlotCommon):
+        (JSC::ProxyObject::performPut):
+        (JSC::performProxyCall):
+        (JSC::performProxyConstruct):
+        (JSC::ProxyObject::performDelete):
+        (JSC::ProxyObject::performPreventExtensions):
+        (JSC::ProxyObject::performIsExtensible):
+        (JSC::ProxyObject::performDefineOwnProperty):
+        (JSC::ProxyObject::performGetOwnPropertyNames):
+        (JSC::ProxyObject::getOwnPropertyNames):
+        (JSC::ProxyObject::getPropertyNames):
+        (JSC::ProxyObject::getOwnNonIndexPropertyNames):
+        (JSC::ProxyObject::performSetPrototype):
+        (JSC::ProxyObject::performGetPrototype):
+        * runtime/ProxyObject.h:
+        (JSC::ProxyObject::create):
+        * tests/stress/proxy-stack-overflow-exceptions.js: Added.
+        (shouldThrowStackOverflow):
+        (const.emptyFunction):
+        (makeLongProxyChain):
+        (shouldThrowStackOverflow.longProxyChain):
+        (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain1):
+        (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain2):
+        (shouldThrowStackOverflow.effecivelyCyclicProxyProtoChain3):
+        (shouldThrowStackOverflow.longProxyChainBind):
+        (shouldThrowStackOverflow.longProxyChainPropertyAccess):
+        (shouldThrowStackOverflow.longProxyChainReflectConstruct):
+        (shouldThrowStackOverflow.longProxyChainReflectSet):
+        (shouldThrowStackOverflow.longProxyChainReflectOwnKeys):
+        (shouldThrowStackOverflow.longProxyChainGetPrototypeOf):
+        (shouldThrowStackOverflow.longProxyChainSetPrototypeOf):
+        (shouldThrowStackOverflow.longProxyChainGetOwnPropertyDescriptor):
+        (shouldThrowStackOverflow.longProxyChainDefineProperty):
+        (shouldThrowStackOverflow.longProxyChainIsExtensible):
+        (shouldThrowStackOverflow.longProxyChainPreventExtensions):
+        (shouldThrowStackOverflow.longProxyChainDeleteProperty):
+        (shouldThrowStackOverflow.longProxyChainWithScope):
+        (shouldThrowStackOverflow.longProxyChainWithScope2):
+        (shouldThrowStackOverflow.longProxyChainWithScope3):
+        (shouldThrowStackOverflow.longProxyChainArrayPrototypePush):
+        (shouldThrowStackOverflow.longProxyChainWithScope4):
+        (shouldThrowStackOverflow.longProxyChainCall):
+        (shouldThrowStackOverflow.longProxyChainConstruct):
+        (shouldThrowStackOverflow.longProxyChainHas):
+
</ins><span class="cx"> 2016-05-28  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSGlobalLexicalEnvironment leaks SegmentedVector due to lack of destructor.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -1288,7 +1288,7 @@
</span><span class="cx">                 799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 79B00CBC1C6AB07E0088C65D /* ProxyConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CB81C6AB07E0088C65D /* ProxyConstructor.cpp */; };
</span><span class="cx">                 79B00CBD1C6AB07E0088C65D /* ProxyConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B00CB91C6AB07E0088C65D /* ProxyConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */; };
</del><ins>+                79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79B00CBA1C6AB07E0088C65D /* ProxyObject.cpp */; settings = {COMPILER_FLAGS = &quot;-fno-optimize-sibling-calls&quot;; }; };
</ins><span class="cx">                 79B00CBF1C6AB07E0088C65D /* ProxyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 79B00CBB1C6AB07E0088C65D /* ProxyObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 79C4B15D1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */; };
</span><span class="cx">                 79C4B15E1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 79C4B15C1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -218,7 +218,7 @@
</span><span class="cx">         length = jsCast&lt;DirectArguments*&gt;(cell)-&gt;length(callFrame);
</span><span class="cx">         break;
</span><span class="cx">     case ScopedArgumentsType:
</span><del>-        length =jsCast&lt;ScopedArguments*&gt;(cell)-&gt;length(callFrame);
</del><ins>+        length = jsCast&lt;ScopedArguments*&gt;(cell)-&gt;length(callFrame);
</ins><span class="cx">         break;
</span><span class="cx">     case StringType:
</span><span class="cx">         callFrame-&gt;vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame,  arguments));
</span><span class="lines">@@ -226,8 +226,11 @@
</span><span class="cx">     default:
</span><span class="cx">         ASSERT(arguments.isObject());
</span><span class="cx">         length = getLength(callFrame, jsCast&lt;JSObject*&gt;(cell));
</span><ins>+        if (UNLIKELY(callFrame-&gt;hadException()))
+            return 0;
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     
</span><span class="cx">     if (length &gt;= firstVarArgOffset)
</span><span class="cx">         length -= firstVarArgOffset;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeInternalFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/InternalFunction.cpp (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/InternalFunction.cpp        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/runtime/InternalFunction.cpp        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -109,16 +109,16 @@
</span><span class="cx">                 return structure;
</span><span class="cx"> 
</span><span class="cx">             // Note, Reflect.construct might cause the profile to churn but we don't care.
</span><del>-            JSObject* prototype = jsDynamicCast&lt;JSObject*&gt;(newTarget.get(exec, exec-&gt;propertyNames().prototype));
-            if (exec-&gt;hadException())
</del><ins>+            JSValue prototypeValue = newTarget.get(exec, exec-&gt;propertyNames().prototype);
+            if (UNLIKELY(vm.exception()))
</ins><span class="cx">                 return nullptr;
</span><del>-            if (prototype)
</del><ins>+            if (JSObject* prototype = jsDynamicCast&lt;JSObject*&gt;(prototypeValue))
</ins><span class="cx">                 return targetFunction-&gt;rareData(vm)-&gt;createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass);
</span><span class="cx">         } else {
</span><del>-            JSObject* prototype = jsDynamicCast&lt;JSObject*&gt;(newTarget.get(exec, exec-&gt;propertyNames().prototype));
-            if (exec-&gt;hadException())
</del><ins>+            JSValue prototypeValue = newTarget.get(exec, exec-&gt;propertyNames().prototype);
+            if (UNLIKELY(vm.exception()))
</ins><span class="cx">                 return nullptr;
</span><del>-            if (prototype) {
</del><ins>+            if (JSObject* prototype = jsDynamicCast&lt;JSObject*&gt;(prototypeValue)) {
</ins><span class="cx">                 // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target.
</span><span class="cx">                 // Thus, we don't care about the cost of looking up the structure from our hash table every time.
</span><span class="cx">                 return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.h (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.h        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.h        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -352,7 +352,12 @@
</span><span class="cx"> {
</span><span class="cx">     if (isJSArray(obj))
</span><span class="cx">         return jsCast&lt;JSArray*&gt;(obj)-&gt;length();
</span><del>-    return obj-&gt;get(exec, exec-&gt;propertyNames().length).toUInt32(exec);
</del><ins>+
+    VM&amp; vm = exec-&gt;vm();
+    JSValue lengthValue = obj-&gt;get(exec, vm.propertyNames-&gt;length);
+    if (UNLIKELY(vm.exception()))
+        return UINT_MAX;
+    return lengthValue.toUInt32(exec);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -282,6 +282,8 @@
</span><span class="cx">         PropertySlot toStringTagSlot(thisObject, PropertySlot::InternalMethodType::Get);
</span><span class="cx">         if (thisObject-&gt;getPropertySlot(exec, toStringTagSymbol, toStringTagSlot)) {
</span><span class="cx">             JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol);
</span><ins>+            if (UNLIKELY(vm.exception()))
+                return JSValue::encode(JSValue());
</ins><span class="cx">             if (stringTag.isString()) {
</span><span class="cx">                 JSRopeString::RopeBuilder ropeBuilder(vm);
</span><span class="cx">                 ropeBuilder.append(vm.smallStrings.objectStringStart());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeProxyObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -34,6 +34,9 @@
</span><span class="cx"> #include &quot;SlotVisitorInlines.h&quot;
</span><span class="cx"> #include &quot;StructureInlines.h&quot;
</span><span class="cx"> 
</span><ins>+// Note that this file is compile with -fno-optimize-sibling-calls because we rely on the machine stack
+// growing larger for throwing OOM errors for when we have an effectively cyclic prototype chain.
+
</ins><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ProxyObject);
</span><span class="lines">@@ -95,7 +98,7 @@
</span><span class="cx"> static EncodedJSValue performProxyGet(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName, JSObject* slotBase)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><del>-    if (!vm.isSafeToRecurse()) {
</del><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
</ins><span class="cx">         throwStackOverflowError(exec);
</span><span class="cx">         return JSValue::encode(JSValue());
</span><span class="cx">     }
</span><span class="lines">@@ -155,6 +158,10 @@
</span><span class="cx"> bool ProxyObject::performInternalMethodGetOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx">     JSObject* target = this-&gt;target();
</span><span class="cx"> 
</span><span class="cx">     auto performDefaultGetOwnProperty = [&amp;] {
</span><span class="lines">@@ -257,6 +264,10 @@
</span><span class="cx"> bool ProxyObject::performHasProperty(ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx">     JSObject* target = this-&gt;target();
</span><span class="cx">     slot.setValue(this, None, jsUndefined()); // Nobody should rely on our value, but be safe and protect against any bad actors reading our value.
</span><span class="cx"> 
</span><span class="lines">@@ -318,6 +329,10 @@
</span><span class="cx"> 
</span><span class="cx"> bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><ins>+    if (UNLIKELY(!exec-&gt;vm().isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx">     slot.disableCaching();
</span><span class="cx">     slot.setIsTaintedByProxy();
</span><span class="cx">     switch (slot.internalMethodType()) {
</span><span class="lines">@@ -353,7 +368,7 @@
</span><span class="cx"> bool ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPut)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><del>-    if (!vm.isSafeToRecurse()) {
</del><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
</ins><span class="cx">         throwStackOverflowError(exec);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -445,6 +460,10 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL performProxyCall(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return JSValue::encode(JSValue());
+    }
</ins><span class="cx">     ProxyObject* proxy = jsCast&lt;ProxyObject*&gt;(exec-&gt;callee());
</span><span class="cx">     JSValue handlerValue = proxy-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull())
</span><span class="lines">@@ -490,6 +509,10 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL performProxyConstruct(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return JSValue::encode(JSValue());
+    }
</ins><span class="cx">     ProxyObject* proxy = jsCast&lt;ProxyObject*&gt;(exec-&gt;callee());
</span><span class="cx">     JSValue handlerValue = proxy-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull())
</span><span class="lines">@@ -541,6 +564,10 @@
</span><span class="cx"> bool ProxyObject::performDelete(ExecState* exec, PropertyName propertyName, DefaultDeleteFunction performDefaultDelete)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (vm.propertyNames-&gt;isPrivateName(Identifier::fromUid(&amp;vm, propertyName.uid())))
</span><span class="cx">         return performDefaultDelete();
</span><span class="lines">@@ -613,6 +640,10 @@
</span><span class="cx"> bool ProxyObject::performPreventExtensions(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     JSValue handlerValue = this-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull()) {
</span><span class="lines">@@ -661,6 +692,10 @@
</span><span class="cx"> bool ProxyObject::performIsExtensible(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     JSValue handlerValue = this-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull()) {
</span><span class="lines">@@ -715,6 +750,10 @@
</span><span class="cx"> bool ProxyObject::performDefineOwnProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor&amp; descriptor, bool shouldThrow)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     JSObject* target = this-&gt;target();
</span><span class="cx">     auto performDefaultDefineOwnProperty = [&amp;] {
</span><span class="lines">@@ -808,6 +847,10 @@
</span><span class="cx"> void ProxyObject::performGetOwnPropertyNames(ExecState* exec, PropertyNameArray&amp; trapResult, EnumerationMode enumerationMode)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return;
+    }
</ins><span class="cx">     JSValue handlerValue = this-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull()) {
</span><span class="cx">         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
</span><span class="lines">@@ -947,6 +990,11 @@
</span><span class="cx">     thisObject-&gt;performGetOwnPropertyNames(exec, propertyNameArray, enumerationMode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ProxyObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray&amp; propertyNameArray, EnumerationMode enumerationMode)
+{
+    JSObject::getPropertyNames(object, exec, propertyNameArray, enumerationMode);
+}
+
</ins><span class="cx"> void ProxyObject::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode)
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -968,6 +1016,10 @@
</span><span class="cx">     ASSERT(prototype.isObject() || prototype.isNull());
</span><span class="cx"> 
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     JSValue handlerValue = this-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull()) {
</span><span class="lines">@@ -1028,6 +1080,10 @@
</span><span class="cx"> JSValue ProxyObject::performGetPrototype(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><ins>+    if (UNLIKELY(!vm.isSafeToRecurse())) {
+        throwStackOverflowError(exec);
+        return JSValue();
+    }
</ins><span class="cx"> 
</span><span class="cx">     JSValue handlerValue = this-&gt;handler();
</span><span class="cx">     if (handlerValue.isNull()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeProxyObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ProxyObject.h (201494 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ProxyObject.h        2016-05-29 04:47:41 UTC (rev 201494)
+++ trunk/Source/JavaScriptCore/runtime/ProxyObject.h        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -36,8 +36,6 @@
</span><span class="cx"> public:
</span><span class="cx">     typedef JSNonFinalObject Base;
</span><span class="cx"> 
</span><del>-    // We lie an say we override getPropertyNames() because it prevents
-    // property name enumeration caching.
</del><span class="cx">     const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | ProhibitsPropertyCaching;
</span><span class="cx"> 
</span><span class="cx">     static ProxyObject* create(ExecState* exec, JSGlobalObject* globalObject, JSValue target, JSValue handler)
</span><span class="lines">@@ -87,6 +85,7 @@
</span><span class="cx">     static bool isExtensible(JSObject*, ExecState*);
</span><span class="cx">     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&amp;, bool shouldThrow);
</span><span class="cx">     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</span><ins>+    static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</ins><span class="cx">     static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</span><span class="cx">     static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</span><span class="cx">     static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressproxystackoverflowexceptionsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/proxy-stack-overflow-exceptions.js (0 => 201495)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/proxy-stack-overflow-exceptions.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/proxy-stack-overflow-exceptions.js        2016-05-29 19:01:36 UTC (rev 201495)
</span><span class="lines">@@ -0,0 +1,161 @@
</span><ins>+function shouldThrowStackOverflow(f) {
+    let threw = false;
+    const verbose = false;
+    try {
+        f();
+    } catch(e) {
+        threw = e instanceof RangeError;
+    }
+    if (!threw)
+        throw new Error(&quot;No stack overflow error thrown.&quot;);
+    if (verbose)
+        print(&quot;passed test: &quot; + f + &quot;\n\n&quot;);
+}
+
+const emptyFunction = function() { };
+let seenStartObjects = new Map;
+function makeLongProxyChain(startObject = emptyFunction) {
+    if (seenStartObjects.has(startObject))
+        return seenStartObjects.get(startObject);
+
+    let p = new Proxy(startObject, { });
+    for (let i = 0; i &lt; 500000; i++)
+        p = new Proxy(p, {});
+    seenStartObjects.set(startObject, p);
+    return p;
+}
+
+shouldThrowStackOverflow(function longProxyChain() {
+    let f = makeLongProxyChain();
+    f.name;
+});
+
+shouldThrowStackOverflow(function effecivelyCyclicProxyProtoChain1() {
+    let t = {};
+    let p = new Proxy(t, {}); 
+    Object.setPrototypeOf(t, p); 
+    t.propertyDoesNotExist;
+});
+
+shouldThrowStackOverflow(function effecivelyCyclicProxyProtoChain2() {
+    let t = {};
+    let p = new Proxy(t, {}); 
+    Object.setPrototypeOf(t, p); 
+    for (var k in p)
+        break;
+});
+
+shouldThrowStackOverflow(function effecivelyCyclicProxyProtoChain3() {
+    let t = {}; 
+    let p = new Proxy(t, {});
+    Object.setPrototypeOf(t, p);
+    Object.prototype.toString.call(p);
+});
+
+shouldThrowStackOverflow(function longProxyChainBind() {
+    let p = makeLongProxyChain();
+    Function.prototype.bind.call(p)
+});
+
+shouldThrowStackOverflow(function longProxyChainPropertyAccess() {
+    let p = makeLongProxyChain();
+    p.nonExistentProperty;
+});
+
+shouldThrowStackOverflow(function longProxyChainReflectConstruct() {
+    let p = makeLongProxyChain();
+    Reflect.construct(Array, [], p);
+});
+
+shouldThrowStackOverflow(function longProxyChainReflectSet() {
+    let p = makeLongProxyChain();
+    Reflect.set([null], 0, 0, p);
+});
+
+shouldThrowStackOverflow(function longProxyChainReflectOwnKeys() {
+    let p = makeLongProxyChain();
+    Reflect.ownKeys(p);
+});
+
+shouldThrowStackOverflow(function longProxyChainGetPrototypeOf() {
+    let p = makeLongProxyChain();
+    Reflect.getPrototypeOf(p);
+});
+
+shouldThrowStackOverflow(function longProxyChainSetPrototypeOf() {
+    let p = makeLongProxyChain();
+    Reflect.setPrototypeOf(p, null);
+});
+
+shouldThrowStackOverflow(function longProxyChainGetOwnPropertyDescriptor() {
+    let p = makeLongProxyChain();
+    Reflect.getOwnPropertyDescriptor(p, &quot;&quot;);
+});
+
+shouldThrowStackOverflow(function longProxyChainDefineProperty() {
+    let p = makeLongProxyChain();
+    Reflect.defineProperty(p, &quot;&quot;, {});
+});
+
+shouldThrowStackOverflow(function longProxyChainIsExtensible() {
+    let p = makeLongProxyChain();
+    Reflect.isExtensible(p);
+});
+
+shouldThrowStackOverflow(function longProxyChainPreventExtensions() {
+    let p = makeLongProxyChain();
+    Reflect.preventExtensions(p)
+});
+
+shouldThrowStackOverflow(function longProxyChainDeleteProperty() {
+    let p = makeLongProxyChain();
+    Reflect.deleteProperty(p, &quot;&quot;);
+});
+
+shouldThrowStackOverflow(function longProxyChainWithScope() {
+    let p = makeLongProxyChain();
+    with (p) {
+        propertyLookup;
+    }
+});
+
+shouldThrowStackOverflow(function longProxyChainWithScope2() {
+    let p = makeLongProxyChain();
+    with (p) {
+        storeToProperty = 0;
+    }
+});
+
+shouldThrowStackOverflow(function longProxyChainWithScope3() {
+    let p = makeLongProxyChain();
+    with (p) {
+        someFunctionPropertyLookup()
+    }
+});
+
+shouldThrowStackOverflow(function longProxyChainArrayPrototypePush() {
+    let p = makeLongProxyChain();
+    Array.prototype.push.call(p, 0);
+});
+
+shouldThrowStackOverflow(function longProxyChainWithScope4() {
+    let p = makeLongProxyChain();
+    with (p) {
+        eval(&quot;&quot;);
+    }
+});
+
+shouldThrowStackOverflow(function longProxyChainCall() {
+    let p = makeLongProxyChain();
+    p();
+});
+
+shouldThrowStackOverflow(function longProxyChainConstruct() {
+    let p = makeLongProxyChain();
+    new p;
+});
+
+shouldThrowStackOverflow(function longProxyChainHas() {
+    let p = makeLongProxyChain();
+    Reflect.has(p, &quot;foo&quot;);
+});
</ins></span></pre>
</div>
</div>

</body>
</html>