typeof(regexp from sandbox) is "function" (bug 607799, r=brendan).
authorAndreas Gal <gal@mozilla.com>
Wed, 10 Nov 2010 15:56:00 -0800
changeset 57775 f52f5d7feb298aa1edf851cb56c97f8ea5745de7
parent 57774 eaaae3775c0084a9e6c05d70540ac0eb0d11e0e8
child 57776 9af757c2776a5dc11a70170c37c102775cf6d842
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbrendan
bugs607799
milestone2.0b8pre
typeof(regexp from sandbox) is "function" (bug 607799, r=brendan).
js/src/js.msg
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/tests/js1_8_5/regress/jstests.list
js/src/tests/js1_8_5/regress/regress-607799.js
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -337,8 +337,9 @@ MSG_DEF(JSMSG_BAD_PARSE_NODE,         25
 MSG_DEF(JSMSG_NOT_EXPECTED_TYPE,      255, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}")
 MSG_DEF(JSMSG_CALLER_IS_STRICT,       256, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
 MSG_DEF(JSMSG_NEED_DEBUG_MODE,        257, 0, JSEXN_ERR, "function can be called only in debug mode")
 MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
 MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")
 MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
 MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,    261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
 MSG_DEF(JSMSG_SC_RECURSION,           262, 0, JSEXN_INTERNALERR, "recursive object")
+MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT,   263, 0, JSEXN_TYPEERR, "can't wrap XML objects")
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -273,16 +273,23 @@ bool
 JSProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
 {
     JS_ASSERT(OperationInProgress(cx, proxy));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                         JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
     return false;
 }
 
+JSType
+JSProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
+{
+    JS_ASSERT(OperationInProgress(cx, proxy));
+    return proxy->isFunctionProxy() ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
+}
+
 void
 JSProxyHandler::finalize(JSContext *cx, JSObject *proxy)
 {
 }
 
 void
 JSProxyHandler::trace(JSTracer *trc, JSObject *proxy)
 {
@@ -787,16 +794,30 @@ JSProxy::call(JSContext *cx, JSObject *p
 
 bool
 JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
 {
     AutoPendingProxyOperation pending(cx, proxy);
     return proxy->getProxyHandler()->construct(cx, proxy, argc, argv, rval);
 }
 
+bool
+JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
+{
+    AutoPendingProxyOperation pending(cx, proxy);
+    return proxy->getProxyHandler()->hasInstance(cx, proxy, vp, bp);
+}
+
+JSType
+JSProxy::typeOf(JSContext *cx, JSObject *proxy)
+{
+    AutoPendingProxyOperation pending(cx, proxy);
+    return proxy->getProxyHandler()->typeOf(cx, proxy);
+}
+
 JSString *
 JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
 {
     AutoPendingProxyOperation pending(cx, proxy);
     return proxy->getProxyHandler()->obj_toString(cx, proxy);
 }
 
 JSString *
@@ -901,35 +922,42 @@ proxy_TraceObject(JSTracer *trc, JSObjec
     MarkValue(trc, obj->getProxyPrivate(), "private");
     MarkValue(trc, obj->getProxyExtra(), "extra");
     if (obj->isFunctionProxy()) {
         MarkValue(trc, GetCall(obj), "call");
         MarkValue(trc, GetConstruct(obj), "construct");
     }
 }
 
-void
+static void
 proxy_Finalize(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isProxy());
     if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
         obj->getProxyHandler()->finalize(cx, obj);
 }
 
 static JSBool
 proxy_HasInstance(JSContext *cx, JSObject *proxy, const Value *v, JSBool *bp)
 {
     AutoPendingProxyOperation pending(cx, proxy);
     bool b;
-    if (!proxy->getProxyHandler()->hasInstance(cx, proxy, v, &b))
+    if (!JSProxy::hasInstance(cx, proxy, v, &b))
         return false;
     *bp = !!b;
     return true;
 }
 
+static JSType
+proxy_TypeOf(JSContext *cx, JSObject *proxy)
+{
+    JS_ASSERT(proxy->isProxy());
+    return JSProxy::typeOf(cx, proxy);
+}
+
 JS_FRIEND_API(Class) ObjectProxyClass = {
     "Proxy",
     Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3),
     PropertyStub,   /* addProperty */
     PropertyStub,   /* delProperty */
     PropertyStub,   /* getProperty */
     PropertyStub,   /* setProperty */
     EnumerateStub,
@@ -948,17 +976,17 @@ JS_FRIEND_API(Class) ObjectProxyClass = 
         proxy_LookupProperty,
         proxy_DefineProperty,
         proxy_GetProperty,
         proxy_SetProperty,
         proxy_GetAttributes,
         proxy_SetAttributes,
         proxy_DeleteProperty,
         NULL,       /* enumerate       */
-        NULL,       /* typeof          */
+        proxy_TypeOf,
         proxy_TraceObject,
         NULL,       /* fix             */
         NULL,       /* thisObject      */
         proxy_Finalize, /* clear */
     }
 };
 
 JS_FRIEND_API(Class) OuterWindowProxyClass = {
@@ -1016,22 +1044,16 @@ proxy_Construct(JSContext *cx, uintN arg
     JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
     JS_ASSERT(proxy->isProxy());
     Value rval;
     bool ok = JSProxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), &rval);
     *vp = rval;
     return ok;
 }
 
-static JSType
-proxy_TypeOf_fun(JSContext *cx, JSObject *obj)
-{
-    return JSTYPE_FUNCTION;
-}
-
 JS_FRIEND_API(Class) FunctionProxyClass = {
     "Proxy",
     Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(5),
     PropertyStub,   /* addProperty */
     PropertyStub,   /* delProperty */
     PropertyStub,   /* getProperty */
     PropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1050,17 +1072,17 @@ JS_FRIEND_API(Class) FunctionProxyClass 
         proxy_LookupProperty,
         proxy_DefineProperty,
         proxy_GetProperty,
         proxy_SetProperty,
         proxy_GetAttributes,
         proxy_SetAttributes,
         proxy_DeleteProperty,
         NULL,       /* enumerate       */
-        proxy_TypeOf_fun,
+        proxy_TypeOf,
         proxy_TraceObject,
         NULL,       /* fix             */
         NULL,       /* thisObject      */
         NULL,       /* clear           */
     }
 };
 
 JS_FRIEND_API(JSObject *)
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -75,16 +75,17 @@ class JS_FRIEND_API(JSProxyHandler) {
     virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoIdVector &props);
     virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, js::Value *vp);
 
     /* Spidermonkey extensions. */
     virtual bool call(JSContext *cx, JSObject *proxy, uintN argc, js::Value *vp);
     virtual bool construct(JSContext *cx, JSObject *proxy,
                                           uintN argc, js::Value *argv, js::Value *rval);
     virtual bool hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp);
+    virtual JSType typeOf(JSContext *cx, JSObject *proxy);
     virtual JSString *obj_toString(JSContext *cx, JSObject *proxy);
     virtual JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
     virtual void finalize(JSContext *cx, JSObject *proxy);
     virtual void trace(JSTracer *trc, JSObject *proxy);
 
     virtual bool isOuterWindow() {
         return false;
     }
@@ -118,16 +119,18 @@ class JSProxy {
     static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
     static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
     static bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoIdVector &props);
     static bool iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp);
 
     /* Spidermonkey extensions. */
     static bool call(JSContext *cx, JSObject *proxy, uintN argc, js::Value *vp);
     static bool construct(JSContext *cx, JSObject *proxy, uintN argc, js::Value *argv, js::Value *rval);
+    static bool hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp);
+    static JSType typeOf(JSContext *cx, JSObject *proxy);
     static JSString *obj_toString(JSContext *cx, JSObject *proxy);
     static JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
 };
 
 /* Shared between object and function proxies. */
 const uint32 JSSLOT_PROXY_HANDLER = 0;
 const uint32 JSSLOT_PROXY_PRIVATE = 1;
 const uint32 JSSLOT_PROXY_EXTRA   = 2;
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -245,16 +245,22 @@ JSWrapper::construct(JSContext *cx, JSOb
 bool
 JSWrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp)
 {
     const jsid id = JSID_VOID;
     JSBool b;
     GET(JS_HasInstance(cx, wrappedObject(wrapper), Jsvalify(*vp), &b) && Cond(b, bp));
 }
 
+JSType
+JSWrapper::typeOf(JSContext *cx, JSObject *wrapper)
+{
+    return TypeOfValue(cx, ObjectValue(*wrappedObject(wrapper)));
+}
+
 JSString *
 JSWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
 {
     JSString *str;
     if (!enter(cx, wrapper, JSID_VOID, GET))
         return NULL;
     str = obj_toStringHelper(cx, wrappedObject(wrapper));
     leave(cx, wrapper);
@@ -291,16 +297,20 @@ JSWrapper::leave(JSContext *cx, JSObject
 
 JSWrapper JSWrapper::singleton((uintN)0);
 
 JSObject *
 JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
                JSWrapper *handler)
 {
     JS_ASSERT(parent);
+    if (obj->isXML()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WRAP_XML_OBJECT);
+        return NULL;
+    }
     return NewProxyObject(cx, handler, ObjectValue(*obj), proto, parent,
                           obj->isCallable() ? obj : NULL, NULL);
 }
 
 /* Compartments. */
 
 namespace js {
 
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -79,16 +79,17 @@ class JS_FRIEND_API(JSWrapper) : public 
     virtual bool enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props);
     virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, js::Value *vp);
 
     /* Spidermonkey extensions. */
     virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp);
     virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *argv,
                            js::Value *rval);
     virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const js::Value *vp, bool *bp);
+    virtual JSType typeOf(JSContext *cx, JSObject *proxy);
     virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper);
     virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
 
     virtual void trace(JSTracer *trc, JSObject *wrapper);
 
     /* Policy enforcement traps. */
     enum Action { GET, SET, CALL };
     virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act);
--- a/js/src/tests/js1_8_5/regress/jstests.list
+++ b/js/src/tests/js1_8_5/regress/jstests.list
@@ -45,11 +45,12 @@ script regress-596805-2.js
 script regress-597870.js
 fails-if(!xulRuntime.shell) script regress-597945-1.js
 script regress-597945-2.js
 script regress-598176.js
 script regress-600067.js
 script regress-600137.js
 script regress-601399.js
 script regress-602621.js
+fails-if(!xulRuntime.shell) script regress-607799.js
 fails-if(!xulRuntime.shell) script regress-607863.js
 script regress-610026.js
 script regress-609617.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-607799.js
@@ -0,0 +1,1 @@
+reportCompare(typeof(evalcx("/x/")), "object")