diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 35d5caedc3..a8bc678630 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -690,7 +690,7 @@ UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleVal if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); - if (arg < argsobj->initialLength()) { + if (argsobj->isElement(arg)) { argsobj->setElement(cx, arg, vp); return result.succeed(); } diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 63dc044b0f..59097b710a 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -283,6 +283,20 @@ class ArgumentsObject : public NativeObject bool markElementDeleted(JSContext* cx, uint32_t i); + /* + * Return true if the index is a valid element index for this arguments + * object. + * + * Returning true here doesn't imply that the element value can be read + * through |ArgumentsObject::element()|. For example, unmapped arguments + * objects can have an element index property redefined without having marked + * the element as deleted. Instead, use |maybeGetElement()| or manually check + * for |hasOverriddenElement()|. + */ + bool isElement(uint32_t i) const { + return i < initialLength() && !isElementDeleted(i); + } + /* * An ArgumentsObject serves two roles: * - a real object, accessed through regular object operations, e.g..,