From 9d05ca7b20e30454b9751e00a8765feebac58a53 Mon Sep 17 00:00:00 2001 From: davidot Date: Mon, 15 Aug 2022 21:25:23 +0200 Subject: [PATCH] LibJS: Don't assume a this argument for function.prototype.bind Assuming we had at least one argument meant that the ...arg count would underflow causing the bound function to have length 0 instead of the given length when binding with no arguments. --- .../Libraries/LibJS/Runtime/FunctionPrototype.cpp | 2 +- .../builtins/Function/Function.prototype.bind.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 2fab7b2f4f..771a4e3f8d 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -103,7 +103,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind) auto* function = TRY(BoundFunction::create(global_object, target, this_argument, move(arguments))); // 4. Let argCount be the number of elements in args. - auto arg_count = vm.argument_count() - 1; + auto arg_count = vm.argument_count() > 0 ? vm.argument_count() - 1 : 0; // 5. Perform ? CopyNameAndLength(F, Target, "bound", argCount). TRY(copy_name_and_length(global_object, *function, target, "bound"sv, arg_count)); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.bind.js b/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.bind.js index b121f6a888..3af8cb2b27 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.bind.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.bind.js @@ -126,6 +126,19 @@ describe("bound function |this|", () => { test("arrow functions cannot be bound", () => { expect((() => this).bind("foo")()).toBe(globalThis); }); + + test("length of original function is used for bound function", () => { + [0, 1, 2147483647, 2147483648, 2147483649].forEach(value => { + function emptyFunction() {} + + Object.defineProperty(emptyFunction, "length", { value }); + + expect(emptyFunction.bind().length).toBe(value); + expect(emptyFunction.bind(null).length).toBe(value); + expect(emptyFunction.bind(null, 0).length).toBe(Math.max(0, value - 1)); + expect(emptyFunction.bind(null, 0, 1, 2).length).toBe(Math.max(0, value - 3)); + }); + }); }); describe("bound function constructors", () => {