فهرست منبع

VSO 8207235: Reflect.apply and Reflect.construct require `argumentsList` params (and the value must be an array or array-like object).

Doug Ilijev 9 سال پیش
والد
کامیت
ac44cffb6b
4فایلهای تغییر یافته به همراه80 افزوده شده و 12 حذف شده
  1. 1 0
      lib/Parser/rterrors.h
  2. 9 0
      lib/Runtime/Library/JavascriptReflect.cpp
  3. 58 0
      test/es6/ReflectApiTests.js
  4. 12 12
      test/wasm/api.js

+ 1 - 0
lib/Parser/rterrors.h

@@ -363,6 +363,7 @@ RT_ERROR_MSG(JSERR_InvalidOperationOnTypedArray, 5664, "", "The operation is not
 RT_ERROR_MSG(JSERR_CannotSuspendBuffer, 5665, "", "Current agent cannot be suspended", kjstRangeError, 0)
 RT_ERROR_MSG(JSERR_CantDeleteNonConfigProp, 5666, "Cannot delete non-configurable property '%s'", "Cannot delete non-configurable property", kjstTypeError, 0)
 RT_ERROR_MSG(JSERR_CantRedefineProp, 5667, "Cannot redefine property '%s'", "Cannot redefine property", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_FunctionArgument_NeedArrayLike, 5668, "%s: argument is not an array or array-like object", "Array or array-like object expected", kjstTypeError, 0)
 
 // WebAssembly Errors
 RT_ERROR_MSG(WASMERR_WasmCompileError, 7000, "%s", "Compilation failed.", kjstWebAssemblyCompileError, 0)

+ 9 - 0
lib/Runtime/Library/JavascriptReflect.cpp

@@ -354,6 +354,10 @@ namespace Js
         }
         Var thisArgument = args.Info.Count > 2 ? args[2] : undefinedValue;
         Var argArray = args.Info.Count > 3 ? args[3] : undefinedValue;
+        if (!(JavascriptOperators::IsObjectType(JavascriptOperators::GetTypeId(argArray))))
+        {
+            JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedArrayLike, _u("Reflect.apply"));
+        }
 
         return JavascriptFunction::ApplyHelper(RecyclableObject::FromVar(target), thisArgument, argArray, scriptContext);
     }
@@ -405,6 +409,11 @@ namespace Js
         }
 
         Var argArray = args.Info.Count > 2 ? args[2] : undefinedValue;
+        if (!(JavascriptOperators::IsObjectType(JavascriptOperators::GetTypeId(argArray))))
+        {
+            JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedArrayLike, _u("Reflect.construct"));
+        }
+
         return JavascriptFunction::ConstructHelper(RecyclableObject::FromVar(target), thisArg, newTarget, argArray, scriptContext);
     }
 }

+ 58 - 0
test/es6/ReflectApiTests.js

@@ -17,6 +17,64 @@ var tests = [
            assert.isFalse(Reflect.set({ p: 43 }, 'p', 42, receiver), "For existing accessor property on receiver [[Set]] returns false even when an own descriptor exists on the target");
        }
    },
+   {
+       name: "Reflect.apply API",
+       body: function () {
+           function foo() {}
+
+           assert.throws(function() { Reflect.apply() }, TypeError, "", "Reflect.apply: argument is not a Function object");
+
+           assert.throws(function() { Reflect.apply(foo) }, TypeError, "argumentsList default == undefined", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined) }, TypeError, "argumentsList default == undefined", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined, undefined) }, TypeError, "argumentsList == undefined", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined, null) }, TypeError, "argumentsList == null", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined, false) }, TypeError, "argumentsList == false", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined, 1) }, TypeError, "argumentsList == 1", "Reflect.apply: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.apply(foo, undefined, Number(42)) }, TypeError, "argumentsList == Number(42)", "Reflect.apply: argument is not an array or array-like object");
+
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, {}) });
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, []) });
+
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Int32Array()) }, "TypedArray should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Error()) }, "Error should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Proxy({}, {})) }, "Proxy should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Promise(r => r())) }, "Promise should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Number(42)) }, "a Number object should be a valid value for arguments");
+
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, Function("return 123")) }, "a Function object should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.apply(foo, undefined, new Function("return 123")) }, "a Function object should be a valid value for arguments");
+       }
+   },
+   {
+       name: "Reflect.construct API",
+       body: function () {
+           function foo() {}
+
+           assert.throws(function() { Reflect.construct() }, TypeError, "" ,"'target' is not a constructor");
+
+           assert.throws(function() { Reflect.construct(foo) }, TypeError, "argumentsList default == undefined" ,"Reflect.construct: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.construct(foo, undefined) }, TypeError, "argumentsList == undefined" ,"Reflect.construct: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.construct(foo, null) }, TypeError, "argumentsList == null" ,"Reflect.construct: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.construct(foo, false) }, TypeError, "argumentsList == false" ,"Reflect.construct: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.construct(foo, 1) }, TypeError, "argumentsList == 1" ,"Reflect.construct: argument is not an array or array-like object");
+           assert.throws(function() { Reflect.construct(foo, Number(42)) }, TypeError, "argumentsList == Number(42)" ,"Reflect.construct: argument is not an array or array-like object");
+
+           assert.doesNotThrow(function() { Reflect.construct(foo, {}) });
+           assert.doesNotThrow(function() { Reflect.construct(foo, []) });
+           assert.doesNotThrow(function() { Reflect.construct(foo, [], Array) });
+
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Int32Array()) }, "TypedArray should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Error()) }, "Error should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Proxy({}, {})) }, "Proxy should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Promise(r => r())) }, "Promise should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Number(42)) }, "a Number object should be a valid value for arguments");
+
+           assert.doesNotThrow(function() { Reflect.construct(foo, Function("return 123")) }, "a Function object should be a valid value for arguments");
+           assert.doesNotThrow(function() { Reflect.construct(foo, new Function("return 123")) }, "a Function object should be a valid value for arguments");
+
+           assert.throws(function() { Reflect.construct(Reflect.apply, undefined) }, TypeError, "" ,"'target' is not a constructor");
+       }
+   },
    {
        name: "Reflect.construct",
        body: function () {

+ 12 - 12
test/wasm/api.js

@@ -178,12 +178,12 @@ async function testMemoryApi(baseModule) {
     () => new WebAssembly.Memory(),
     () => new WebAssembly.Memory(0),
     () => new WebAssembly.Memory(""),
-    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, null),
-    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, {}),
-    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, baseModule),
-    () => Reflect.apply(WebAssembly.Memory.prototype.grow, null),
-    () => Reflect.apply(WebAssembly.Memory.prototype.grow, {}),
-    () => Reflect.apply(WebAssembly.Memory.prototype.grow, baseModule),
+    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, null, []),
+    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, {}, []),
+    () => Reflect.apply(WebAssembly.Memory.prototype.buffer, baseModule, []),
+    () => Reflect.apply(WebAssembly.Memory.prototype.grow, null, []),
+    () => Reflect.apply(WebAssembly.Memory.prototype.grow, {}, []),
+    () => Reflect.apply(WebAssembly.Memory.prototype.grow, baseModule, []),
     // todo:: test invalid memory imports, need to find the spec
   ]);
   const toHex = v => typeof v === "number" ? `0x${v.toString(16)}` : "undefined";
@@ -262,12 +262,12 @@ async function testTableApi(baseModule) {
     () => new WebAssembly.Table(0),
     () => new WebAssembly.Table(""),
     () => new WebAssembly.Table({element: "notanyfunc", initial: 30, maximum: 100}),
-    () => Reflect.apply(WebAssembly.Table.prototype.length, null),
-    () => Reflect.apply(WebAssembly.Table.prototype.length, {}),
-    () => Reflect.apply(WebAssembly.Table.prototype.length, baseModule),
-    () => Reflect.apply(WebAssembly.Table.prototype.grow, null),
-    () => Reflect.apply(WebAssembly.Table.prototype.grow, {}),
-    () => Reflect.apply(WebAssembly.Table.prototype.grow, baseModule),
+    () => Reflect.apply(WebAssembly.Table.prototype.length, null, []),
+    () => Reflect.apply(WebAssembly.Table.prototype.length, {}, []),
+    () => Reflect.apply(WebAssembly.Table.prototype.length, baseModule, []),
+    () => Reflect.apply(WebAssembly.Table.prototype.grow, null, []),
+    () => Reflect.apply(WebAssembly.Table.prototype.grow, {}, []),
+    () => Reflect.apply(WebAssembly.Table.prototype.grow, baseModule, []),
     () => Reflect.apply(WebAssembly.Table.prototype.get, null, [0]),
     () => Reflect.apply(WebAssembly.Table.prototype.get, {}, [0]),
     () => Reflect.apply(WebAssembly.Table.prototype.get, baseModule, [0]),