From 14f16a831d7be6e7124d244d3b53216f5b95143a Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Thu, 9 Feb 2017 15:25:25 -0800 Subject: [PATCH] Bug 1338323 - Don't attach SetArrayLength stub if length is not writable. (r=evilpie) --HG-- extra : rebase_source : bf0328f031bc5b2b178ac59049dd75713960b8be --- js/src/jit/CacheIR.cpp | 6 +++++- js/src/jit/VMFunctions.cpp | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index a217afa7b34d..f7c3a236fda4 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -2213,8 +2213,12 @@ bool SetPropIRGenerator::tryAttachSetArrayLength(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId) { - if (!obj->is() || !JSID_IS_ATOM(id, cx_->names().length)) + if (!obj->is() || + !JSID_IS_ATOM(id, cx_->names().length) || + !obj->as().lengthIsWritable()) + { return false; + } maybeEmitIdGuard(id); writer.guardClass(objId, GuardClassKind::Array); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 9ef25d28eb42..2a9db6e24f5a 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -401,8 +401,25 @@ SetArrayLength(JSContext* cx, HandleObject obj, HandleValue value, bool strict) RootedId id(cx, NameToId(cx->names().length)); ObjectOpResult result; - return ArraySetLength(cx, array, id, JSPROP_PERMANENT, value, result) && - result.checkStrictErrorOrWarning(cx, obj, id, strict); + + // SetArrayLength is called by IC stubs for SetProp and SetElem on arrays' + // "length" property. + // + // ArraySetLength below coerces |value| before checking for length being + // writable, and in the case of illegal values, will throw RangeError even + // when "length" is not writable. This is incorrect observable behavior, + // as a regular [[Set]] operation will check for "length" being + // writable before attempting any assignment. + // + // So, perform ArraySetLength if and only if "length" is writable. + if (array->lengthIsWritable()) { + if (!ArraySetLength(cx, array, id, JSPROP_PERMANENT, value, result)) + return false; + } else { + MOZ_ALWAYS_TRUE(result.fail(JSMSG_READ_ONLY)); + } + + return result.checkStrictErrorOrWarning(cx, obj, id, strict); } bool