Reputation: 116273
Does JavaScript have undefined behaviour (similar to C) or is it completely well-defined by the spec, and deterministic?
Note that I am discarding implementation bugs and spec divergences. I am also discarding stuff like Math.random()
and Date.now()
.
Is there a piece of JavaScript code for which the behaviour is not completely determined by the JavaScript specifications, and, as such, has "undefined behaviour"?
Upvotes: 25
Views: 4080
Reputation: 58560
Firstly, the ECMA-262 standard that defined the language informally known as JavaScript uses the terms "implementation-dependent" and "implementation-defined" without ever defining what these terms mean. Effectively, all those behaviors are undefined; no requirements are given about what should happen. An implementation that crashes or behaves unpredictably is conforming; certainly so if it documents that behavior: that crashing or erratic behavior is then what is defined by the implementation. By contrast, the ISO C standard formally defines terms like "unspecified behavior", "implementation-defined behavior" and "undefined behavior". These words actually mean something wherever they occur.
Secondly, the ECMA-262 standard is mum about implementation limits. That does not mean they are not there. For instance, can a Javascript program in a given specific implementation have any depth of recursion? Any number of function arguments? Any depth of lexical scoping? Can it allocate any number of objects? Certainly not, right? The word "limit" doesn't even appear anywhere in ECMA-262 2018, except as a function argument name. The document doesn't say, for instance, that a conforming implementation of ECMAScript must allow functions with 64 parmeters. Therefore, it comes to reason that implementations must support functions with any number of parameters thrown at them. If we make a function with ten million parameters, and the implementation crashes, it is nonconforming; nowhere does ECMA-262 state that such a failure is permitted. If a C compiler crashes due to ten million parameters in a function, we can squarely pinpoint that as an issue in the program: it is exceeding a minimum implementation limit documented in the standard, and thus fails to be strictly conforming (a formal term). This is a case of undefined behavior: it involves a non-portable program, for which the standard imposes no requirements (does not require implementations to handle that many function arguments).
Upvotes: 0
Reputation: 664346
There's a lot of things in the spec that are explicitly left to the implementation. Especially when it comes to Host Objects, there can be many quirks. Examples that have nothing to do with host objects:
The values of the [[Prototype]] and [[Class]] internal properties of the global object are implementation-dependent.
15.1.2.2 parseInt (string , radix)
[If there are too many significant digits] mathInt may be an implementation-dependent approximation to the mathematical integer value that is represented by Z in radix-R notation.
15.3.4.2 Function.prototype.toString
An implementation-dependent representation of the function is returned.
Nearly all Date parse / stringifiy algorithms are implementation-dependent, this includes toLocaleString
, toString
, parse
and the Date
constructor.
15.4.4.11 Array.prototype.sort (comparefn) - likely the best example:
If comparefn is not undefined and is not a consistent comparison function for the elements of this array, the behaviour of sort is implementation-defined.
[…] If proto is not null and there exists an integer j such that all of the conditions below are satisfied then the behaviour of sort is implementation-defined:
- obj is sparse (15.4)
- 0 ≤ j < len
The behaviour of sort is also implementation defined if obj is sparse and any of the following conditions are true:
- The [[Extensible]] internal property of obj is false.
- Any array index property of obj whose name is a nonnegative integer less than len is a data property whose [[Configurable]] attribute is false.
The behaviour of sort is also implementation defined if any array index property of obj whose name is a nonnegative integer less than len is an accessor property or is a data property whose [[Writable]] attribute is false.
And most promiently:
Perform an implementation-dependent sequence of calls […]
15.5.4.9 String.prototype.localeCompare (that)
The two Strings are compared in an implementation-defined fashion
15.5.4.11 String.prototype.replace [In replacement symbols, if the number is greater than the number of groups], the result is implementation-defined.
I'll just stop listing here, you can search on through the spec. Other notable places may be the toLocaleString
methods, or the implementation-dependent approximations returned by the Math
methods.
Upvotes: 11
Reputation: 81133
Any program which invokes C-style Undefined Behavior in response to any input will be unsuitable for use with untrustworthy input. While there are many situations where the ECMAScript specification doesn't specify precise behaviors, but it doesn't give implementations the same freedom to negate the laws of time and causality that C compilers have with Undefined Behavior.
Upvotes: 3
Reputation: 340723
I found few example, quoting of ECMAScript Language Specification (emphasis mine):
In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other.
If the toFixed method is called with more than one argument, then the behaviour is undefined (see clause 15).
If the toExponential method is called with more than one argument, then the behaviour is undefined (see clause 15).
If the toPrecision method is called with more than one argument, then the behaviour is undefined (see clause 15).
When the UTC function is called with fewer than two arguments, the behaviour is implementation-dependent.
Upvotes: 9
Reputation: 120178
I found
Array.sort(compareFunction);
in the case where compareFunction doesn't behave properly (i.e. return consistent results for the same inputs).
From the specification:
If comparefn is not undefined and is not a consistent comparison function for the elements of this array (see below), the behaviour of sort is implementation-defined.
Upvotes: 6