diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-03-19 09:21:55 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-03-19 09:23:23 +0100 |
commit | faa5f0df26e09d1f2e633618476294d112c24322 (patch) | |
tree | d9cc82bd54a71c51146924e975aef4861e67cd27 /js/src/vm/ErrorObject.cpp | |
parent | 393ee744a8d44494a2a3750aec8e3e9845ecf780 (diff) | |
parent | 77e607426f03524bdaf06bfc6799f5e9273051b9 (diff) | |
download | UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.gz UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.lz UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.xz UXP-faa5f0df26e09d1f2e633618476294d112c24322.zip |
Prototypes should be regular objects.
This resolves #76
Merged remote-tracking branch 'janek/js_error_ordinary-object_1'
Diffstat (limited to 'js/src/vm/ErrorObject.cpp')
-rw-r--r-- | js/src/vm/ErrorObject.cpp | 69 |
1 files changed, 39 insertions, 30 deletions
diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index 47b61b57b..d8d29830b 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -164,29 +164,25 @@ js::ErrorObject::getOrCreateErrorReport(JSContext* cx) } static bool -ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName, - MutableHandle<ErrorObject*> error) +FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result) { - const Value& thisValue = args.thisv(); - - if (!thisValue.isObject()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, - InformalValueTypeName(thisValue)); - return false; - } - - // Walk up the prototype chain until we find the first ErrorObject that has - // the slots we need. This allows us to support the poor-man's subclassing - // of error: Object.create(Error.prototype). - - RootedObject target(cx, CheckedUnwrap(&thisValue.toObject())); + // Walk up the prototype chain until we find an error object instance or + // prototype object. This allows code like: + // Object.create(Error.prototype).stack + // or + // function NYI() { } + // NYI.prototype = new Error; + // (new NYI).stack + // to continue returning stacks that are useless, but at least don't throw. + + RootedObject target(cx, CheckedUnwrap(obj)); if (!target) { JS_ReportErrorASCII(cx, "Permission denied to access object"); return false; } RootedObject proto(cx); - while (!target->is<ErrorObject>()) { + while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) { if (!GetPrototype(cx, target, &proto)) return false; @@ -194,7 +190,7 @@ ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName // We walked the whole prototype chain and did not find an Error // object. JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - js_Error_str, fnName, thisValue.toObject().getClass()->name); + js_Error_str, "(get stack)", obj->getClass()->name); return false; } @@ -205,19 +201,40 @@ ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName } } - error.set(&target->as<ErrorObject>()); + result.set(target); return true; } + +static MOZ_ALWAYS_INLINE bool +IsObject(HandleValue v) +{ + return v.isObject(); +} + /* static */ bool js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - Rooted<ErrorObject*> error(cx); - if (!ErrorObject_checkAndUnwrapThis(cx, args, "(get stack)", &error)) + // We accept any object here, because of poor-man's subclassing of Error. + return CallNonGenericMethod<IsObject, getStack_impl>(cx, args); +} + +/* static */ bool +js::ErrorObject::getStack_impl(JSContext* cx, const CallArgs& args) +{ + RootedObject thisObj(cx, &args.thisv().toObject()); + + RootedObject obj(cx); + if (!FindErrorInstanceOrPrototype(cx, thisObj, &obj)) return false; - RootedObject savedFrameObj(cx, error->stack()); + if (!obj->is<ErrorObject>()) { + args.rval().setString(cx->runtime()->emptyString); + return true; + } + + RootedObject savedFrameObj(cx, obj->as<ErrorObject>().stack()); RootedString stackString(cx); if (!BuildStackString(cx, savedFrameObj, &stackString)) return false; @@ -245,12 +262,6 @@ js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp) return true; } -static MOZ_ALWAYS_INLINE bool -IsObject(HandleValue v) -{ - return v.isObject(); -} - /* static */ bool js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp) { @@ -262,9 +273,7 @@ js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp) /* static */ bool js::ErrorObject::setStack_impl(JSContext* cx, const CallArgs& args) { - const Value& thisValue = args.thisv(); - MOZ_ASSERT(thisValue.isObject()); - RootedObject thisObj(cx, &thisValue.toObject()); + RootedObject thisObj(cx, &args.thisv().toObject()); if (!args.requireAtLeast(cx, "(set stack)", 1)) return false; |