diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 70a1772801e2..4bdde51f5fbb 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -576,6 +576,13 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return XPC_XOW_RewrapIfNeeded(cx, obj, vp); } + JSObject *proto = nsnull; // Initialize this to quiet GCC. + JSBool checkProto = + (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)); + if (checkProto) { + proto = JS_GetPrototype(cx, wrappedObj); + } + // Same origin, pass this request along as though nothing interesting // happened. jsid asId; @@ -591,6 +598,27 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } + if (checkProto && JS_GetPrototype(cx, wrappedObj) != proto) { + // Ensure that this __proto__ setting didn't create a cycle. The JS + // engine tries to do this, but XOWs confuse it. So here we deal with + // them by unwrapping each step up the prototype chain. + + JSObject *oldProto = proto; + proto = wrappedObj; + while ((proto = JS_GetPrototype(cx, proto)) != nsnull) { + JSObject *unwrapped = GetWrappedObject(cx, proto); + if (unwrapped) { + proto = unwrapped; + } + + if (proto == wrappedObj) { + JS_SetPrototype(cx, wrappedObj, oldProto); + JS_ReportError(cx, "cyclic __proto__ value"); + return JS_FALSE; + } + } + } + // Don't call XPC_XOW_RewrapIfNeeded for same origin properties. We only // need to wrap window, document and location. if (JSVAL_IS_PRIMITIVE(*vp)) { diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 8e2ae32825b6..3b652949f9f5 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -64,6 +64,7 @@ const char* XPCJSRuntime::mStrings[] = { , "COMObject" // IDX_COMOBJECT , "supports" // IDX_ACTIVEX_SUPPORTS #endif + , "__proto__" // IDX_PROTO }; /***************************************************************************/ diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 07822a8a56df..e0519bb3da09 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -650,6 +650,7 @@ public: IDX_COM_OBJECT , IDX_ACTIVEX_SUPPORTS , #endif + IDX_PROTO , IDX_TOTAL_COUNT // just a count of the above };