mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Implement an iterator hook for cross origin wrappers to avoid wrongly walking up the prototype chain during enumeration. bug 390947, r+a=brendan sr=jst
This commit is contained in:
parent
20e5bb075c
commit
3b183e4e87
@ -65,6 +65,7 @@
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsinterp.h"
|
||||
#include "jsiter.h"
|
||||
#include "jslock.h"
|
||||
#include "jsmath.h"
|
||||
#include "jsnum.h"
|
||||
@ -86,10 +87,6 @@
|
||||
#include "jsxml.h"
|
||||
#endif
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
#include "jsiter.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VA_LIST_AS_ARRAY
|
||||
#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
|
||||
#else
|
||||
@ -5549,6 +5546,12 @@ JS_ThrowReportedError(JSContext *cx, const char *message,
|
||||
return js_ErrorToException(cx, message, reportp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ThrowStopIteration(JSContext *cx)
|
||||
{
|
||||
return js_ThrowStopIteration(cx);
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* Get the owning thread id of a context. Returns 0 if the context is not
|
||||
|
@ -2465,6 +2465,12 @@ extern JS_PUBLIC_API(JSBool)
|
||||
JS_ThrowReportedError(JSContext *cx, const char *message,
|
||||
JSErrorReport *reportp);
|
||||
|
||||
/*
|
||||
* Throws a StopIteration exception on cx.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_ThrowStopIteration(JSContext *cx);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
/*
|
||||
|
@ -270,8 +270,8 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
js_ThrowStopIteration(JSContext *cx, JSObject *obj)
|
||||
JSBool
|
||||
js_ThrowStopIteration(JSContext *cx)
|
||||
{
|
||||
jsval v;
|
||||
|
||||
@ -295,7 +295,7 @@ iterator_next(JSContext *cx, uintN argc, jsval *vp)
|
||||
|
||||
if (*vp == JSVAL_HOLE) {
|
||||
*vp = JSVAL_NULL;
|
||||
js_ThrowStopIteration(cx, obj);
|
||||
js_ThrowStopIteration(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
@ -916,7 +916,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||
*rval = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return js_ThrowStopIteration(cx, obj);
|
||||
return js_ThrowStopIteration(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -990,7 +990,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp)
|
||||
switch (op) {
|
||||
case JSGENOP_NEXT:
|
||||
case JSGENOP_SEND:
|
||||
return js_ThrowStopIteration(cx, obj);
|
||||
return js_ThrowStopIteration(cx);
|
||||
case JSGENOP_THROW:
|
||||
JS_SetPendingException(cx, vp[2]);
|
||||
return JS_FALSE;
|
||||
|
@ -77,6 +77,9 @@ js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval);
|
||||
extern void
|
||||
js_CloseNativeIterator(JSContext *cx, JSObject *iterobj);
|
||||
|
||||
extern JSBool
|
||||
js_ThrowStopIteration(JSContext *cx);
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
||||
/*
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "nsDOMError.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsobj.h" // For OBJ_GET_PROPERTY.
|
||||
#include "jscntxt.h" // For JSAutoTempValueRooter.
|
||||
#include "XPCWrapper.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDOMWindowCollection.h"
|
||||
@ -87,6 +88,9 @@ XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSObject *)
|
||||
XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
|
||||
|
||||
JSExtendedClass sXPC_XOW_JSClass = {
|
||||
// JSClass (JSExtendedClass.base) initialization
|
||||
{ "XPCCrossOriginWrapper",
|
||||
@ -101,8 +105,13 @@ JSExtendedClass sXPC_XOW_JSClass = {
|
||||
nsnull, nsnull,
|
||||
nsnull, nsnull
|
||||
},
|
||||
|
||||
// JSExtendedClass initialization
|
||||
XPC_XOW_Equality
|
||||
XPC_XOW_Equality,
|
||||
nsnull, // outerObject
|
||||
nsnull, // innerObject
|
||||
XPC_XOW_Iterator,
|
||||
JSCLASS_NO_RESERVED_MEMBERS
|
||||
};
|
||||
|
||||
// The slot that we stick our scope into.
|
||||
@ -813,10 +822,10 @@ XPC_XOW_Finalize(JSContext *cx, JSObject *obj)
|
||||
|
||||
// Now that we have our scope, see if it's going away. If it is,
|
||||
// then our work here is going to be done when we destroy the scope
|
||||
// entirely.
|
||||
// entirely. Scope can be null if we're an enumerating XOW.
|
||||
XPCWrappedNativeScope *scope = reinterpret_cast<XPCWrappedNativeScope *>
|
||||
(JSVAL_TO_PRIVATE(scopeVal));
|
||||
if (XPCWrappedNativeScope::IsDyingScope(scope)) {
|
||||
if (!scope || XPCWrappedNativeScope::IsDyingScope(scope)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -937,6 +946,160 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
|
||||
equality(cx, obj, OBJECT_TO_JSVAL(test), bp);
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(void)
|
||||
IteratorFinalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
jsval v;
|
||||
JS_GetReservedSlot(cx, obj, 0, &v);
|
||||
|
||||
JSIdArray *ida = reinterpret_cast<JSIdArray *>(JSVAL_TO_PRIVATE(v));
|
||||
if (ida) {
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
}
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
IteratorNext(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj = JSVAL_TO_OBJECT(vp[1]);
|
||||
jsval v;
|
||||
|
||||
JS_GetReservedSlot(cx, obj, 0, &v);
|
||||
JSIdArray *ida = reinterpret_cast<JSIdArray *>(JSVAL_TO_PRIVATE(v));
|
||||
|
||||
JS_GetReservedSlot(cx, obj, 1, &v);
|
||||
jsint idx = JSVAL_TO_INT(v);
|
||||
|
||||
if (idx == ida->length) {
|
||||
return JS_ThrowStopIteration(cx);
|
||||
}
|
||||
|
||||
JS_GetReservedSlot(cx, obj, 2, &v);
|
||||
jsid id = ida->vector[idx++];
|
||||
if (JSVAL_TO_BOOLEAN(v)) {
|
||||
if (!JS_IdToValue(cx, id, &v)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = v;
|
||||
} else {
|
||||
// We need to return an [id, value] pair.
|
||||
if (!OBJ_GET_PROPERTY(cx, JS_GetParent(cx, obj), id, &v)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
jsval name;
|
||||
if (!JS_IdToValue(cx, id, &name)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
jsval vec[2] = { name, v };
|
||||
JSAutoTempValueRooter tvr(cx, 2, vec);
|
||||
JSObject *array = JS_NewArrayObject(cx, 2, vec);
|
||||
if (!array) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(array);
|
||||
}
|
||||
|
||||
JS_SetReservedSlot(cx, obj, 1, INT_TO_JSVAL(idx));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSClass IteratorClass = {
|
||||
"XOW iterator", JSCLASS_HAS_RESERVED_SLOTS(3),
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, IteratorFinalize,
|
||||
|
||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||
};
|
||||
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSObject *)
|
||||
XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
|
||||
{
|
||||
// This is rather ugly: we want to use the trick seen in Enumerate,
|
||||
// where we use our wrapper's resolve hook to determine if we should
|
||||
// enumerate a given property. However, we don't want to pollute the
|
||||
// identifiers with a next method, so we create an object that
|
||||
// delegates (via the __proto__ link) to a XOW.
|
||||
|
||||
jsval root = JSVAL_NULL;
|
||||
|
||||
// Root v's address so we can set it and have the right value rooted.
|
||||
JSAutoTempValueRooter tvr(cx, 1, &root);
|
||||
|
||||
JSObject *wrapperIter = JS_NewObject(cx, &sXPC_XOW_JSClass.base, nsnull,
|
||||
JS_GetGlobalForObject(cx, obj));
|
||||
if (!wrapperIter) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
root = OBJECT_TO_JSVAL(wrapperIter);
|
||||
|
||||
JSObject *iterObj = JS_NewObject(cx, &IteratorClass, wrapperIter, obj);
|
||||
if (!iterObj) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
root = OBJECT_TO_JSVAL(iterObj);
|
||||
|
||||
// Do this sooner rather than later to avoid complications in
|
||||
// IteratorFinalize.
|
||||
if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull))) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Initialize iterObj.
|
||||
if (!JS_DefineFunction(cx, iterObj, "next", (JSNative)IteratorNext, 0,
|
||||
JSFUN_FAST_NATIVE)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Initialize our XOW.
|
||||
JSObject *innerObj = GetWrappedObject(cx, obj);
|
||||
if (!innerObj) {
|
||||
ThrowException(NS_ERROR_INVALID_ARG, cx);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
jsval v = OBJECT_TO_JSVAL(innerObj);
|
||||
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) ||
|
||||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sResolvingSlot,
|
||||
JSVAL_FALSE) ||
|
||||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sNumSlots,
|
||||
PRIVATE_TO_JSVAL(nsnull))) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Start enumerating over all of our properties.
|
||||
do {
|
||||
if (!XPCWrapper::Enumerate(cx, iterObj, innerObj)) {
|
||||
return nsnull;
|
||||
}
|
||||
} while ((innerObj = JS_GetPrototype(cx, innerObj)) != nsnull);
|
||||
|
||||
JSIdArray *ida = JS_Enumerate(cx, iterObj);
|
||||
if (!ida) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(ida)) ||
|
||||
!JS_SetReservedSlot(cx, iterObj, 1, JSVAL_ZERO) ||
|
||||
!JS_SetReservedSlot(cx, iterObj, 2, BOOLEAN_TO_JSVAL(keysonly))) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!JS_SetPrototype(cx, iterObj, nsnull)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return iterObj;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
|
@ -106,7 +106,6 @@ XPCWrapper::Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj)
|
||||
|
||||
JSBool ok = JS_TRUE;
|
||||
|
||||
do {
|
||||
JSIdArray *ida = JS_Enumerate(cx, innerObj);
|
||||
if (!ida) {
|
||||
return JS_FALSE;
|
||||
@ -126,10 +125,19 @@ XPCWrapper::Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj)
|
||||
if (prop) {
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
}
|
||||
|
||||
if (pobj != wrapperObj) {
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, wrapperObj, ida->vector[i], JSVAL_VOID,
|
||||
nsnull, nsnull, JSPROP_ENUMERATE | JSPROP_SHARED,
|
||||
nsnull);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
} while (ok && (innerObj = JS_GetPrototype(cx, innerObj)) != nsnull);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -58,13 +58,14 @@ const char* XPCJSRuntime::mStrings[] = {
|
||||
"Function", // IDX_FUNCTION
|
||||
"prototype", // IDX_PROTOTYPE
|
||||
"createInstance", // IDX_CREATE_INSTANCE
|
||||
"item" // IDX_ITEM
|
||||
"item", // IDX_ITEM
|
||||
"__proto__", // IDX_PROTO
|
||||
"__iterator__" // IDX_ITERATOR
|
||||
#ifdef XPC_IDISPATCH_SUPPORT
|
||||
, "GeckoActiveXObject" // IDX_ACTIVEX_OBJECT
|
||||
, "COMObject" // IDX_COMOBJECT
|
||||
, "supports" // IDX_ACTIVEX_SUPPORTS
|
||||
#endif
|
||||
, "__proto__" // IDX_PROTO
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -649,12 +649,13 @@ public:
|
||||
IDX_PROTOTYPE ,
|
||||
IDX_CREATE_INSTANCE ,
|
||||
IDX_ITEM ,
|
||||
IDX_PROTO ,
|
||||
IDX_ITERATOR ,
|
||||
#ifdef XPC_IDISPATCH_SUPPORT
|
||||
IDX_ACTIVEX_OBJECT ,
|
||||
IDX_COM_OBJECT ,
|
||||
IDX_ACTIVEX_SUPPORTS ,
|
||||
#endif
|
||||
IDX_PROTO ,
|
||||
IDX_TOTAL_COUNT // just a count of the above
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user