From 29ac09479665a7f3f4342684c554f27fe712ecc5 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Thu, 3 Mar 2011 14:24:13 -0600 Subject: [PATCH] Bug 636697 - Crash calling null setter in js_watch_set. r=brendan. --- js/src/jsdbgapi.cpp | 24 ++++++++++++++----- js/src/tests/js1_8_5/extensions/jstests.list | 1 + .../js1_8_5/extensions/regress-636697.js | 11 +++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 js/src/tests/js1_8_5/extensions/regress-636697.js diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 3d809486d5a..d6064d84d51 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -718,19 +718,30 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) wp = (JSWatchPoint *)wp->links.next) { const Shape *shape = wp->shape; if (wp->object == obj && SHAPE_USERID(shape) == id && !(wp->flags & JSWP_HELD)) { + bool ok; + Value old; + uint32 slot; + const Shape *needMethodSlotWrite = NULL; + wp->flags |= JSWP_HELD; DBG_UNLOCK(rt); jsid propid = shape->id; shape = obj->nativeLookup(propid); + if (!shape) { + /* + * This happens if the watched property has been deleted, but a + * prototype has a watched accessor property with the same + * name. See bug 636697. + */ + ok = true; + goto out; + } JS_ASSERT(IsWatchedProperty(cx, shape)); - jsid userid = SHAPE_USERID(shape); /* Determine the property's old value. */ - bool ok; - uint32 slot = shape->slot; - Value old = obj->containsSlot(slot) ? obj->nativeGetSlot(slot) : UndefinedValue(); - const Shape *needMethodSlotWrite = NULL; + slot = shape->slot; + old = obj->containsSlot(slot) ? obj->nativeGetSlot(slot) : UndefinedValue(); if (shape->isMethod()) { /* * We get here in two cases: (1) the existing watched property @@ -793,7 +804,8 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) ? ExternalInvoke(cx, ObjectValue(*obj), ObjectValue(*CastAsObject(wp->setter)), 1, vp, vp) - : CallJSPropertyOpSetter(cx, wp->setter, obj, userid, strict, vp); + : CallJSPropertyOpSetter(cx, wp->setter, obj, SHAPE_USERID(shape), + strict, vp); } else if (shape == needMethodSlotWrite) { /* See comment above about needMethodSlotWrite. */ obj->nativeSetSlot(shape->slot, *vp); diff --git a/js/src/tests/js1_8_5/extensions/jstests.list b/js/src/tests/js1_8_5/extensions/jstests.list index e60130b9e9c..687ed545776 100644 --- a/js/src/tests/js1_8_5/extensions/jstests.list +++ b/js/src/tests/js1_8_5/extensions/jstests.list @@ -34,3 +34,4 @@ script regress-627984-6.js script regress-627984-7.js script regress-630377.js script regress-631723.js +script regress-636697.js diff --git a/js/src/tests/js1_8_5/extensions/regress-636697.js b/js/src/tests/js1_8_5/extensions/regress-636697.js new file mode 100644 index 00000000000..6b3b1de370b --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/regress-636697.js @@ -0,0 +1,11 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var a = {set p(x) {}}; +a.watch('p', function () {}); +var b = Object.create(a); +b.watch('p', function () {}); +delete b.p; +b.p = 0; + +reportCompare(0, 0, 'ok');