Bug 901979 - Assertion failure: !global->nativeLookup(cx, id), at ../jsobjinlines.h:1125. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 23 Oct 2013 11:42:25 -0500
changeset 165692 9f4815b4ad647f0724fb9ec5a794031817a998aa
parent 165691 1fbd79b930b2a1347b439a9fb67ee78099c63caf
child 165693 eafe6b0acd33631cedf91cfe2f6245ea634bf2f9
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs901979
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 901979 - Assertion failure: !global->nativeLookup(cx, id), at ../jsobjinlines.h:1125. r=Waldo.
js/src/jit-test/tests/proxy/bug901979-1.js
js/src/jit-test/tests/proxy/bug901979-2.js
js/src/jsobj.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug901979-1.js
@@ -0,0 +1,12 @@
+// A proxy on the prototype chain of the global can't intercept lazy definition of globals.
+// Thanks to André Bargull for this one.
+
+var global = this;
+var status = "pass";
+var handler = {
+  get: function get(t, pk, r) { status = "FAIL get"; },
+  has: function has(t, pk) { status = "FAIL has"; }
+};
+Object.prototype.__proto__ = new Proxy(Object.create(null), handler);
+Map;
+assertEq(status, "pass");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug901979-2.js
@@ -0,0 +1,31 @@
+// A proxy on the prototype chain of the global should not observe anything at
+// all about lazy resolution of globals.
+
+var global = this;
+var status = "pass";
+
+// This is a little tricky. There are two proxies.
+// 1. handler is a proxy that fails the test if you try to call a method on it.
+var metaHandler = {
+  get: _ => { status = "SMASH"; },
+  has: _ => { status = "SMASH"; },
+  invoke: _ => { status = "SMASH"; }
+};
+var handler = new Proxy({}, metaHandler);
+
+// 2. Then we create a proxy using 'handler' as its handler. This means the test
+//    will fail if *any* method of the handler is called, not just get/has/invoke.
+var angryProxy = new Proxy(Object.create(null), handler);
+this.__proto__ = angryProxy;
+Object.prototype.__proto__ = angryProxy;
+
+// Trip the alarm once, to make sure the proxies are working.
+this.nonExistingProperty;
+assertEq(status, "SMASH");
+
+// OK. Reset the status and run the actual test.
+status = "pass";
+Map;
+ArrayBuffer;
+Date;
+assertEq(status, "pass");
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3551,16 +3551,20 @@ DefinePropertyOrElement(typename Executi
             return false;
         RootedValue nvalue(cx, value);
         return NativeSet<mode>(ExecutionModeTraits<mode>::toContextType(cx),
                                obj, obj, shape, setterIsStrict, &nvalue);
     }
     return true;
 }
 
+static bool
+NativeLookupOwnProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, unsigned flags,
+                        MutableHandle<Shape*> shapep);
+
 bool
 js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
                          PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                          unsigned flags, int shortid, unsigned defineHow /* = 0 */)
 {
     JS_ASSERT((defineHow & ~(DNP_DONT_PURGE | DNP_SKIP_TYPE)) == 0);
     JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS));
 
@@ -3574,23 +3578,21 @@ js::DefineNativeProperty(ExclusiveContex
     RootedShape shape(cx);
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         /* Type information for getter/setter properties is unknown. */
         AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
         MarkTypePropertyConfigured(cx, obj, id);
 
         /*
          * If we are defining a getter whose setter was already defined, or
-         * vice versa, finish the job via obj->changeProperty, and refresh the
-         * property cache line for (obj, id) to map shape.
+         * vice versa, finish the job via obj->changeProperty.
          */
-        RootedObject pobj(cx);
-        if (!baseops::LookupProperty<CanGC>(cx, obj, id, &pobj, &shape))
+        if (!NativeLookupOwnProperty(cx, obj, id, flags, &shape))
             return false;
-        if (shape && pobj == obj) {
+        if (shape) {
             if (IsImplicitDenseElement(shape)) {
                 if (!JSObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
                     return false;
                 shape = obj->nativeLookup(cx, id);
             }
             if (shape->isAccessorDescriptor()) {
                 shape = JSObject::changeProperty<SequentialExecution>(cx, obj, shape, attrs,
                                                                       JSPROP_GETTER | JSPROP_SETTER,
@@ -3600,18 +3602,16 @@ js::DefineNativeProperty(ExclusiveContex
                                                                       (attrs & JSPROP_SETTER)
                                                                       ? setter
                                                                       : shape->setter());
                 if (!shape)
                     return false;
             } else {
                 shape = nullptr;
             }
-        } else {
-            shape = nullptr;
         }
     }
 
     /*
      * Purge the property cache of any properties named by id that are about
      * to be shadowed in obj's scope chain unless it is known a priori that it
      * is not possible.
      */
@@ -3795,16 +3795,30 @@ LookupOwnPropertyWithFlagsInline(Exclusi
             return true;
         }
     }
 
     *donep = false;
     return true;
 }
 
+static bool
+NativeLookupOwnProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, unsigned flags,
+                        MutableHandle<Shape*> shapep)
+{
+    RootedObject pobj(cx);
+    bool done;
+
+    if (!LookupOwnPropertyWithFlagsInline<CanGC>(cx, obj, id, flags, &pobj, shapep, &done))
+        return false;
+    if (!done || pobj != obj)
+        shapep.set(nullptr);
+    return true;
+}
+
 template <AllowGC allowGC>
 static JS_ALWAYS_INLINE bool
 LookupPropertyWithFlagsInline(ExclusiveContext *cx,
                               typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                               typename MaybeRooted<jsid, allowGC>::HandleType id,
                               unsigned flags,
                               typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
                               typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)