Browse Source

LibJS: Do not revisit already visited values in update_function_name()

Fixes #3471, adds a test.
AnotherTest 4 years ago
parent
commit
21f513fe0f
2 changed files with 19 additions and 2 deletions
  1. 12 2
      Libraries/LibJS/AST.cpp
  2. 7 0
      Libraries/LibJS/Tests/functions/function-name.js

+ 12 - 2
Libraries/LibJS/AST.cpp

@@ -26,6 +26,7 @@
  */
 
 #include <AK/HashMap.h>
+#include <AK/HashTable.h>
 #include <AK/ScopeGuard.h>
 #include <AK/StringBuilder.h>
 #include <LibCrypto/BigInt/SignedBigInteger.h>
@@ -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<const JS::Cell*>& 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<Function&>(object);
@@ -61,10 +65,16 @@ static void update_function_name(Value& value, const FlyString& name)
     } else if (object.is_array()) {
         auto& array = static_cast<Array&>(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<const JS::Cell*> visited;
+    update_function_name(value, name, visited);
+}
+
 static String get_function_name(Interpreter& interpreter, Value value)
 {
     if (value.is_symbol())

+ 7 - 0
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");
+});