Browse Source

LibJS: Check validity of computed_property_name() result before using it

This fixes two cases obj[expr] and obj[expr]() (MemberExpression and
CallExpression respectively) when expr throws an exception and results
in an empty value, causing a crash by passing the invalid PropertyName
created by computed_property_name() to Object::get() without checking it
first.

Fixes #3459.
Linus Groh 4 years ago
parent
commit
568d53c9b1

+ 8 - 2
Libraries/LibJS/AST.cpp

@@ -122,7 +122,10 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
         auto* this_value = is_super_property_lookup ? &interpreter.this_value(global_object).as_object() : lookup_target.to_object(interpreter, global_object);
         auto* this_value = is_super_property_lookup ? &interpreter.this_value(global_object).as_object() : lookup_target.to_object(interpreter, global_object);
         if (interpreter.exception())
         if (interpreter.exception())
             return {};
             return {};
-        auto callee = lookup_target.to_object(interpreter, global_object)->get(member_expression.computed_property_name(interpreter, global_object)).value_or(js_undefined());
+        auto property_name = member_expression.computed_property_name(interpreter, global_object);
+        if (!property_name.is_valid())
+            return {};
+        auto callee = lookup_target.to_object(interpreter, global_object)->get(property_name).value_or(js_undefined());
         return { this_value, callee };
         return { this_value, callee };
     }
     }
     return { &global_object, m_callee->execute(interpreter, global_object) };
     return { &global_object, m_callee->execute(interpreter, global_object) };
@@ -1589,7 +1592,10 @@ Value MemberExpression::execute(Interpreter& interpreter, GlobalObject& global_o
     auto* object_result = object_value.to_object(interpreter, global_object);
     auto* object_result = object_value.to_object(interpreter, global_object);
     if (interpreter.exception())
     if (interpreter.exception())
         return {};
         return {};
-    return object_result->get(computed_property_name(interpreter, global_object)).value_or(js_undefined());
+    auto property_name = computed_property_name(interpreter, global_object);
+    if (!property_name.is_valid())
+        return {};
+    return object_result->get(property_name).value_or(js_undefined());
 }
 }
 
 
 Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const
 Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const

+ 8 - 0
Libraries/LibJS/Tests/computed-property-throws.js

@@ -0,0 +1,8 @@
+test("Issue #3459, exception in computed property expression", () => {
+    expect(() => {
+        "foo"[bar];
+    }).toThrow(ReferenceError);
+    expect(() => {
+        "foo"[bar]();
+    }).toThrow(ReferenceError);
+});

+ 1 - 1
Libraries/LibJS/Tests/exception-in-catch-block.js

@@ -1,4 +1,4 @@
-test("Issue #1992, exception thrown in catch {} block", () => {
+test("Issue #3437, exception thrown in catch {} block", () => {
     var tryHasBeenExecuted = false;
     var tryHasBeenExecuted = false;
     var catchHasBeenExecuted = false;
     var catchHasBeenExecuted = false;
     var finallyHasBeenExecuted = false;
     var finallyHasBeenExecuted = false;