1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 05:07:34 +00:00

LibJS: Pass this value to fallback func in Array.prototype.toString()

The existing code looks innocently correct, implementing the following
step:

    3. If IsCallable(func) is false, set func to the intrinsic function
       %Object.prototype.toString%.

as

    return ObjectPrototype::to_string(vm, global_object);

However, this misses the fact that the next step calls the function with
the previously ToObject()'d this value (`array`):

    4. Return ? Call(func, array).

This doesn't happen in the current implementation, which will use the
unaltered this value from the Array.prototype.toString() call, and make
another, unequal object in %Object.prototype.toString%. Since both that
and Array.prototype.toString() do a Get() call on said object, this
behavior is observable (see newly added test).

Fix this by actually doing what the spec says and calling the fallback
function the regular way.
This commit is contained in:
Linus Groh 2022-04-11 22:47:50 +01:00
parent 2af869d018
commit 00b8ce4a6d
4 changed files with 53 additions and 10 deletions

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -302,6 +302,7 @@ void GlobalObject::initialize_global_object()
m_date_constructor_now_function = &m_date_constructor->get_without_side_effects(vm.names.now).as_function();
m_eval_function = &get_without_side_effects(vm.names.eval).as_function();
m_json_parse_function = &get_without_side_effects(vm.names.JSON).as_object().get_without_side_effects(vm.names.parse).as_function();
m_object_prototype_to_string_function = &m_object_prototype->get_without_side_effects(vm.names.toString).as_function();
}
GlobalObject::~GlobalObject() = default;
@ -320,8 +321,9 @@ void GlobalObject::visit_edges(Visitor& visitor)
visitor.visit(m_array_prototype_values_function);
visitor.visit(m_date_constructor_now_function);
visitor.visit(m_eval_function);
visitor.visit(m_throw_type_error_function);
visitor.visit(m_json_parse_function);
visitor.visit(m_object_prototype_to_string_function);
visitor.visit(m_throw_type_error_function);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
visitor.visit(m_##snake_name##_constructor); \