Ecma262: .bind on a function with infinite length has imprecise spec and engine divergences

Created on 11 Sep 2020  路  5Comments  路  Source: tc39/ecma262

function f(){}
Object.defineProperty(f, 'length', { value: Infinity });
console.log(f.bind(0, 1, 2).length);

gives

#### ch
0

#### jsc
0

#### sm
Infinity

#### v8
Infinity

#### xs
9007199254740989

Presumably this is the fault of the following bit of the definition of F.p.bind:

1. Let _targetHasLength_ be ? HasOwnProperty(_Target_, *"length"*).
1. If _targetHasLength_ is *true*, then
  1. Let _targetLen_ be ? Get(_Target_, *"length"*).
  1. If Type(_targetLen_) is Number, then
    1. Set _targetLen_ to ! ToInteger(_targetLen_).
    1. Let _argCount_ be the number of elements in _args_.
    1. Set _L_ to max(_targetLen_ - _argCount_, 0).

Note that ToInteger can return Infinity (for some reason), and hence this does arithmetic on a potentially infinite value, which isn't a thing we've said how to do. So it's unsurprising that engines have different behavior.

We should resolve this. I propose we say that binding a function whose length is Infinity produces a function whose length is Infinity, regardless of how many arguments are provided to bind.

has consensus needs tests normative change web reality

Most helpful comment

Note that implementation divergence occurs well before Infinity:

$ eshost -se 'Object.defineProperties(function(){}, {length:{value:0x8000000000000480}}).bind().length'
#### ChakraCore
2048

#### engine262, JavaScriptCore, QuickJS, SpiderMonkey, V8
9223372036854778000

#### GraalJS
9223372036854776000

#### Moddable XS
9007199254740991

I think there's a reasonable case to be made for limiting length to 2 ** 32 - 1, aligning with arrays and template literals and regular expression captures.

All 5 comments

Hmm, I thought I'd filed an issue for this when it came up on irc a month or two ago, but apparently not - thanks for filing!

I agree that if it's 卤Infinity (or perhaps also NaN? what do engines do there?) the value should be left alone (ie, when targetLen is not finite).

As of r266013, JSC also returns Infinity.
Implementation-wise, I have a slight preference for length being clamped to Number.MAX_SAFE_INTEGER by using ToLength instead of ToInteger.

also NaN? what do engines do there?) the value should be left alone (ie, when targetLen is not finite).

ToInteger returns +0 for NaN (step 2).
test262 coverage was recently updated for NaN, Infinity, and other edge-cases: https://github.com/tc39/test262/pull/2730.

Note that implementation divergence occurs well before Infinity:

$ eshost -se 'Object.defineProperties(function(){}, {length:{value:0x8000000000000480}}).bind().length'
#### ChakraCore
2048

#### engine262, JavaScriptCore, QuickJS, SpiderMonkey, V8
9223372036854778000

#### GraalJS
9223372036854776000

#### Moddable XS
9007199254740991

I think there's a reasonable case to be made for limiting length to 2 ** 32 - 1, aligning with arrays and template literals and regular expression captures.

Via @patrick-soquet:

XS uses ToLength so it returns 9007199254740991 which is Number.MAX_SAFE_INTEGER - 2, because bind is called with two arguments.

That is almost what @shvaikalesh suggests. However, his preference matches @gibson042:

I would support the latest comment in the thread: limiting length to 2 ** 32 - 1

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bkardell picture bkardell  路  3Comments

erights picture erights  路  4Comments

ENvironmentSet picture ENvironmentSet  路  5Comments

AlexSHoffman picture AlexSHoffman  路  3Comments

erights picture erights  路  4Comments