From e8430cf0d31afbbf6c6f3632697e262351b2182e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 3 Jul 2021 01:25:07 +0200 Subject: [PATCH] LibJS: Don't allow `delete super.property` This should throw a ReferenceError, since `delete` is not allowed on super references. --- Userland/Libraries/LibJS/AST.cpp | 2 +- Userland/Libraries/LibJS/Runtime/ErrorTypes.h | 1 + .../Libraries/LibJS/Runtime/Reference.cpp | 41 +++++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 198c573b14..5efd1fcaec 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -769,7 +769,7 @@ Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& if (!property_name.is_valid()) return Reference {}; - return Reference { object_value, property_name, object_value }; + return Reference { object_value, property_name, {} }; } Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index 4995d0843c..01a9d07d35 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -164,6 +164,7 @@ M(TypedArrayPrototypeOneArg, "TypedArray.prototype.{}() requires at least one argument") \ M(TypedArrayFailedSettingIndex, "Failed setting value of index {} of typed array") \ M(UnknownIdentifier, "'{}' is not defined") \ + M(UnsupportedDeleteSuperProperty, "Can't delete a property on 'super'") \ M(URIMalformed, "URI malformed") /* LibWeb bindings */ \ M(NotAByteString, "Argument to {}() must be a byte string") \ M(BadArgCountOne, "{}() needs one argument") \ diff --git a/Userland/Libraries/LibJS/Runtime/Reference.cpp b/Userland/Libraries/LibJS/Runtime/Reference.cpp index f87c8d64ba..8b0311ea29 100644 --- a/Userland/Libraries/LibJS/Runtime/Reference.cpp +++ b/Userland/Libraries/LibJS/Runtime/Reference.cpp @@ -110,26 +110,61 @@ Value Reference::get_value(GlobalObject& global_object, bool throw_if_undefined) bool Reference::delete_(GlobalObject& global_object) { + // 13.5.1.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation + // UnaryExpression : delete UnaryExpression + + // NOTE: The following steps have already been evaluated by the time we get here: + // 1. Let ref be the result of evaluating UnaryExpression. + // 2. ReturnIfAbrupt(ref). + // 3. If ref is not a Reference Record, return true. + + // 4. If IsUnresolvableReference(ref) is true, then if (is_unresolvable()) { + // a. Assert: ref.[[Strict]] is false. VERIFY(!m_strict); + // b. Return true. return true; } auto& vm = global_object.vm(); + // 5. If IsPropertyReference(ref) is true, then if (is_property_reference()) { + // a. Assert: ! IsPrivateReference(ref) is false. + // FIXME: We don't have private references yet. + + // b. If IsSuperReference(ref) is true, throw a ReferenceError exception. + if (is_super_reference()) { + vm.throw_exception(global_object, ErrorType::UnsupportedDeleteSuperProperty); + return false; + } + + // c. Let baseObj be ! ToObject(ref.[[Base]]). auto* base_obj = m_base_value.to_object(global_object); if (!base_obj) return false; - bool succeeded = base_obj->delete_property(m_name); - if (!succeeded && m_strict) { + + // d. Let deleteStatus be ? baseObj.[[Delete]](ref.[[ReferencedName]]). + bool delete_status = base_obj->delete_property(m_name); + + // e. If deleteStatus is false and ref.[[Strict]] is true, throw a TypeError exception. + if (!delete_status && m_strict) { vm.throw_exception(global_object, ErrorType::ReferenceNullishDeleteProperty, m_name.to_value(vm).to_string_without_side_effects(), m_base_value.to_string_without_side_effects()); return false; } - return succeeded; + + // f. Return deleteStatus. + return delete_status; } + // 6. Else, + // a. Let base be ref.[[Base]]. + // b. Assert: base is an Environment Record. + VERIFY(m_base_type == BaseType::Environment); + + // c. Return ? base.DeleteBinding(ref.[[ReferencedName]]). + // FIXME: This is ad-hoc, we should be calling DeleteBinding. return m_base_environment->delete_from_environment(m_name.as_string()); }