From 8a3427845fc5a30f18d273615474b6bdbadd8d8a Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 26 Apr 2026 10:49:29 +0200 Subject: [PATCH] [js] Use isElement in UnmappedArgSetter to check if the argument was marked as deleted. This is more consistent with `UnmappedArgGetter` and better handles the case where the property was marked deleted in `RareArgumentsData` but not actually deleted from the object due to OOM. Unfortunately this scenario is hard to prevent because the property is marked as deleted in the `ArgumentsObject::obj_delProperty` class hook and after that `NativeDeleteProperty` tries to remove the property and this can fail. --- js/src/vm/ArgumentsObject.cpp | 2 +- js/src/vm/ArgumentsObject.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) 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..,