diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 3886950442..96a8d49d14 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -49,10 +50,13 @@ namespace JS { -static void update_function_name(Value& value, const FlyString& name) +static void update_function_name(Value& value, const FlyString& name, HashTable& visited) { if (!value.is_object()) return; + if (visited.contains(value.as_cell())) + return; + visited.set(value.as_cell()); auto& object = value.as_object(); if (object.is_function()) { auto& function = static_cast(object); @@ -61,10 +65,16 @@ static void update_function_name(Value& value, const FlyString& name) } else if (object.is_array()) { auto& array = static_cast(object); for (auto& entry : array.indexed_properties().values_unordered()) - update_function_name(entry.value, name); + update_function_name(entry.value, name, visited); } } +static void update_function_name(Value& value, const FlyString& name) +{ + HashTable visited; + update_function_name(value, name, visited); +} + static String get_function_name(Interpreter& interpreter, Value value) { if (value.is_symbol()) diff --git a/Libraries/LibJS/Tests/functions/function-name.js b/Libraries/LibJS/Tests/functions/function-name.js index b00ec614f2..90520187d9 100644 --- a/Libraries/LibJS/Tests/functions/function-name.js +++ b/Libraries/LibJS/Tests/functions/function-name.js @@ -48,3 +48,10 @@ test("names of native functions", () => { expect((console.debug.name = "warn")).toBe("warn"); expect(console.debug.name).toBe("debug"); }); + +test("cyclic members should not cause infinite recursion (#3471)", () => { + let a = [() => 4]; + a[1] = a; + a = a; + expect(a[0].name).toBe("a"); +});