From bebc345a97be1db2463e859a88e50df686e1ee91 Mon Sep 17 00:00:00 2001 From: "andrea.bergia" Date: Fri, 20 Dec 2024 17:00:32 +0100 Subject: [PATCH] Fix: methods cannot be used as constructor The spec says that invoking a method as a constructor is not valid, but invoking normal functions is. This is, for example, `node`: ```js > o = { method() {}, notAMethod: function() {} } { method: [Function: method], notAMethod: [Function: notAMethod] } > new o.method() Uncaught TypeError: o.method is not a constructor > new o.notAMethod() notAMethod {} ``` This PR implements the same behavior in Rhino, and fixes #1299. --- .../main/java/org/mozilla/javascript/BaseFunction.java | 5 +++++ .../main/java/org/mozilla/javascript/Interpreter.java | 8 ++++++++ .../javascript/tests/harmony/MethodDefinitionTest.java | 3 +++ tests/testsrc/jstests/harmony/method-definition.js | 5 ++++- tests/testsrc/test262.properties | 10 ++++------ 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java index fbaae75043..72c025d872 100644 --- a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java +++ b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java @@ -408,6 +408,11 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar @Override public Scriptable construct(Context cx, Scriptable scope, Object[] args) { + if (cx.getLanguageVersion() >= Context.VERSION_ES6 && this.getHomeObject() != null) { + // Only methods have home objects associated with them + throw ScriptRuntime.typeErrorById("msg.not.ctor", getFunctionName()); + } + Scriptable result = createObject(cx, scope); if (result != null) { Object val = call(cx, scope, result, args); diff --git a/rhino/src/main/java/org/mozilla/javascript/Interpreter.java b/rhino/src/main/java/org/mozilla/javascript/Interpreter.java index a88d181804..bda0716beb 100644 --- a/rhino/src/main/java/org/mozilla/javascript/Interpreter.java +++ b/rhino/src/main/java/org/mozilla/javascript/Interpreter.java @@ -2006,6 +2006,14 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl if (lhs instanceof InterpretedFunction) { InterpretedFunction f = (InterpretedFunction) lhs; if (frame.fnOrScript.securityDomain == f.securityDomain) { + if (cx.getLanguageVersion() >= Context.VERSION_ES6 + && f.getHomeObject() != null) { + // Only methods have home objects associated with + // them + throw ScriptRuntime.typeErrorById( + "msg.not.ctor", f.getFunctionName()); + } + Scriptable newInstance = f.createObject(cx, frame.scope); CallFrame calleeFrame = diff --git a/tests/src/test/java/org/mozilla/javascript/tests/harmony/MethodDefinitionTest.java b/tests/src/test/java/org/mozilla/javascript/tests/harmony/MethodDefinitionTest.java index 6a69604e38..91651e1bf2 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/harmony/MethodDefinitionTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/harmony/MethodDefinitionTest.java @@ -4,8 +4,11 @@ package org.mozilla.javascript.tests.harmony; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.drivers.LanguageVersion; import org.mozilla.javascript.drivers.RhinoTest; import org.mozilla.javascript.drivers.ScriptTestsBase; @RhinoTest("testsrc/jstests/harmony/method-definition.js") +@LanguageVersion(Context.VERSION_ES6) public class MethodDefinitionTest extends ScriptTestsBase {} diff --git a/tests/testsrc/jstests/harmony/method-definition.js b/tests/testsrc/jstests/harmony/method-definition.js index 50c475e480..17bc5a7ccd 100644 --- a/tests/testsrc/jstests/harmony/method-definition.js +++ b/tests/testsrc/jstests/harmony/method-definition.js @@ -63,7 +63,10 @@ assertEquals(123, { }.abc()); // Method is the kind of function, that is non-constructor. -// assertThrows('new (({ a() {} }).a)', TypeError); +assertThrows(function() { + new (({ a() {} }).a) +}, TypeError); +assertNotNull(new (({ notAMethod: function() {} }).notAMethod)); var desc = Object.getOwnPropertyDescriptor({ a() { diff --git a/tests/testsrc/test262.properties b/tests/testsrc/test262.properties index 6f9056d4fb..09e4fa0d85 100644 --- a/tests/testsrc/test262.properties +++ b/tests/testsrc/test262.properties @@ -957,7 +957,7 @@ built-ins/Number 23/335 (6.87%) S9.3.1_A3_T1_U180E.js {unsupported: [u180e]} S9.3.1_A3_T2_U180E.js {unsupported: [u180e]} -built-ins/Object 178/3408 (5.22%) +built-ins/Object 177/3408 (5.19%) assign/assignment-to-readonly-property-of-target-must-throw-a-typeerror-exception.js assign/not-a-constructor.js assign/source-own-prop-error.js @@ -1530,7 +1530,7 @@ built-ins/Promise 392/631 (62.12%) resolve-thenable-deferred.js {unsupported: [async]} resolve-thenable-immed.js {unsupported: [async]} -built-ins/Proxy 76/311 (24.44%) +built-ins/Proxy 73/311 (23.47%) construct/arguments-realm.js construct/call-parameters.js construct/call-parameters-new-target.js @@ -3146,7 +3146,7 @@ built-ins/undefined 0/8 (0.0%) ~intl402 -language/arguments-object 185/263 (70.34%) +language/arguments-object 184/263 (69.96%) mapped/mapped-arguments-nonconfigurable-3.js non-strict mapped/mapped-arguments-nonconfigurable-delete-1.js non-strict mapped/mapped-arguments-nonconfigurable-delete-2.js non-strict @@ -4852,7 +4852,7 @@ language/expressions/new 41/59 (69.49%) ~language/expressions/new.target -language/expressions/object 719/1169 (61.51%) +language/expressions/object 717/1169 (61.33%) dstr/async-gen-meth-ary-init-iter-close.js {unsupported: [async-iteration, async]} dstr/async-gen-meth-ary-init-iter-get-err.js {unsupported: [async-iteration]} dstr/async-gen-meth-ary-init-iter-get-err-array-prototype.js {unsupported: [async-iteration]} @@ -5456,7 +5456,6 @@ language/expressions/object 719/1169 (61.51%) method-definition/gen-yield-spread-arr-multiple.js method-definition/gen-yield-spread-arr-single.js method-definition/gen-yield-spread-obj.js - method-definition/generator-invoke-ctor.js method-definition/generator-invoke-fn-strict.js non-strict method-definition/generator-length-dflt.js method-definition/generator-name-prop-string.js @@ -5475,7 +5474,6 @@ language/expressions/object 719/1169 (61.51%) method-definition/meth-eval-var-scope-syntax-err.js non-strict method-definition/meth-object-destructuring-param-strict-body.js method-definition/meth-rest-param-strict-body.js - method-definition/name-invoke-ctor.js method-definition/name-invoke-fn-strict.js non-strict method-definition/name-length-dflt.js method-definition/name-name-prop-string.js