diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 409fccc0dab0..9025e1945f33 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -809,6 +809,63 @@ Debugger::unwrapDebuggeeValue(JSContext *cx, MutableHandleValue vp) return true; } +/* + * Convert Debugger.Objects in desc to debuggee values. + * Reject non-callable getters and setters. + */ +static bool +CheckArgCompartment(JSContext *cx, JSObject *obj, HandleValue v, + const char *methodname, const char *propname) +{ + if (v.isObject() && v.toObject().compartment() != obj->compartment()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_COMPARTMENT_MISMATCH, + methodname, propname); + return false; + } + return true; +} + +bool +Debugger::unwrapPropDescInto(JSContext *cx, HandleObject obj, Handle wrapped, + MutableHandle unwrapped) +{ + MOZ_ASSERT(!wrapped.isUndefined()); + + unwrapped.set(wrapped); + + if (unwrapped.hasValue()) { + RootedValue value(cx, unwrapped.value()); + if (!unwrapDebuggeeValue(cx, &value) || + !CheckArgCompartment(cx, obj, value, "defineProperty", "value")) + { + return false; + } + unwrapped.setValue(value); + } + + if (unwrapped.hasGet()) { + RootedValue get(cx, unwrapped.getterValue()); + if (!unwrapDebuggeeValue(cx, &get) || + !CheckArgCompartment(cx, obj, get, "defineProperty", "get")) + { + return false; + } + unwrapped.setGetter(get); + } + + if (unwrapped.hasSet()) { + RootedValue set(cx, unwrapped.setterValue()); + if (!unwrapDebuggeeValue(cx, &set) || + !CheckArgCompartment(cx, obj, set, "defineProperty", "set")) + { + return false; + } + unwrapped.setSetter(set); + } + + return true; +} + JSTrapStatus Debugger::handleUncaughtExceptionHelper(Maybe &ac, MutableHandleValue *vp, bool callHook) @@ -5262,7 +5319,7 @@ DebuggerObject_defineProperty(JSContext *cx, unsigned argc, Value *vp) return false; desc.clearPd(); - if (!desc.get().unwrapDebuggerObjectsInto(cx, dbg, obj, desc.address())) + if (!dbg->unwrapPropDescInto(cx, obj, desc, &desc)) return false; if (!desc.checkGetter(cx) || !desc.checkSetter(cx)) return false; @@ -5306,7 +5363,10 @@ DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp) for (size_t i = 0; i < n; i++) { if (!unwrappedDescs.append()) return false; - if (!descs[i].unwrapDebuggerObjectsInto(cx, dbg, obj, &unwrappedDescs[i])) + Handle wrapped = Handle::fromMarkedLocation(&descs[i]); + MutableHandle unwrapped = + MutableHandle::fromMarkedLocation(&unwrappedDescs[i]); + if (!dbg->unwrapPropDescInto(cx, obj, wrapped, unwrapped)) return false; if (!unwrappedDescs[i].checkGetter(cx) || !unwrappedDescs[i].checkSetter(cx)) return false; diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index df6da16ec406..0bc28b238ea0 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -506,6 +506,8 @@ class Debugger : private mozilla::LinkedListElement * happens in the target compartment--rotational symmetry.) */ bool unwrapDebuggeeValue(JSContext *cx, MutableHandleValue vp); + bool unwrapPropDescInto(JSContext *cx, HandleObject obj, Handle wrapped, + MutableHandle unwrapped); /* * Store the Debugger.Frame object for frame in *vp. diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 1538f04af933..703ea069d09d 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -59,63 +59,6 @@ PropDesc::checkSetter(JSContext *cx) return true; } -static bool -CheckArgCompartment(JSContext *cx, JSObject *obj, HandleValue v, - const char *methodname, const char *propname) -{ - if (v.isObject() && v.toObject().compartment() != obj->compartment()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_COMPARTMENT_MISMATCH, - methodname, propname); - return false; - } - return true; -} - -/* - * Convert Debugger.Objects in desc to debuggee values. - * Reject non-callable getters and setters. - */ -bool -PropDesc::unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, HandleObject obj, - PropDesc *unwrapped) const -{ - MOZ_ASSERT(!isUndefined()); - - *unwrapped = *this; - - if (unwrapped->hasValue()) { - RootedValue value(cx, unwrapped->value_); - if (!dbg->unwrapDebuggeeValue(cx, &value) || - !CheckArgCompartment(cx, obj, value, "defineProperty", "value")) - { - return false; - } - unwrapped->value_ = value; - } - - if (unwrapped->hasGet()) { - RootedValue get(cx, unwrapped->get_); - if (!dbg->unwrapDebuggeeValue(cx, &get) || - !CheckArgCompartment(cx, obj, get, "defineProperty", "get")) - { - return false; - } - unwrapped->get_ = get; - } - - if (unwrapped->hasSet()) { - RootedValue set(cx, unwrapped->set_); - if (!dbg->unwrapDebuggeeValue(cx, &set) || - !CheckArgCompartment(cx, obj, set, "defineProperty", "set")) - { - return false; - } - unwrapped->set_ = set; - } - - return true; -} - /* * Rewrap *idp and the fields of *desc for the current compartment. Also: * defining a property on a proxy requires pd_ to contain a descriptor object, diff --git a/js/src/vm/PropDesc.h b/js/src/vm/PropDesc.h index bea886625635..1beae907a1e8 100644 --- a/js/src/vm/PropDesc.h +++ b/js/src/vm/PropDesc.h @@ -12,8 +12,6 @@ namespace js { -class Debugger; - static inline JSPropertyOp CastAsPropertyOp(JSObject *object) { @@ -182,6 +180,11 @@ struct PropDesc { MOZ_ASSERT(hasValue()); return HandleValue::fromMarkedLocation(&value_); } + void setValue(const Value &value) { + MOZ_ASSERT(!isUndefined()); + value_ = value; + hasValue_ = true; + } JSObject * getterObject() const { MOZ_ASSERT(!isUndefined()); @@ -205,6 +208,17 @@ struct PropDesc { return HandleValue::fromMarkedLocation(&set_); } + void setGetter(const Value &getter) { + MOZ_ASSERT(!isUndefined()); + get_ = getter; + hasGet_ = true; + } + void setSetter(const Value &setter) { + MOZ_ASSERT(!isUndefined()); + set_ = setter; + hasSet_ = true; + } + /* * Unfortunately the values produced by these methods are used such that * we can't assert anything here. :-( @@ -224,9 +238,6 @@ struct PropDesc { bool checkGetter(JSContext *cx); bool checkSetter(JSContext *cx); - bool unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, HandleObject obj, - PropDesc *unwrapped) const; - bool wrapInto(JSContext *cx, HandleObject obj, const jsid &id, jsid *wrappedId, PropDesc *wrappedDesc) const; }; @@ -299,6 +310,16 @@ class MutablePropDescOperations : public PropDescOperations return desc()->makeObject(cx); } + void setValue(const Value &value) { + desc()->setValue(value); + } + void setGetter(const Value &getter) { + desc()->setGetter(getter); + } + void setSetter(const Value &setter) { + desc()->setSetter(setter); + } + void setUndefined() { desc()->setUndefined(); } void clearPd() { desc()->clearPd(); } };