24

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"?

Randomblue
  • 112,777
  • 145
  • 353
  • 547

5 Answers5

11

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:

15.1 The Global Object

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.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 7
    Of course, "Implementation-dependent" in JavaScript is nothing like "Undefined Behavior" in C. – supercat Feb 16 '16 at 03:02
  • @supercat: Sure, it's not like [this](https://xkcd.com/292/) or [that](https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633), but the implementation isn't exactly prohibited from crashing the function (runtime exception), whole page, whole browser or whole system. – Bergi Feb 16 '16 at 13:42
  • 2
    The first sentence of the question asks whether it has Undefined Behavior similar to C. While nothing in the Standard prohibits browsers from allowing remote code from crashing the local machine, there is also nothing which could be taken to suggest that browser makers are entitled to assume that code will never receive inputs that would cause it to do certain things. – supercat Feb 16 '16 at 18:50
  • @supercat: I focused on "*Is it completely well-defined by the spec, and deterministic?*". Do you think I should add a notice to the answer that these "implementation-defined" behaviours are not *like undefined behaviour in C*? – Bergi Feb 16 '16 at 18:56
  • I think it's a distinction worth making. Personally, I consider it unfortunate that the authors of the C Standard failed to indicate what while an implementation is allowed to do anything it likes in various cases, in cases where a platform could cheaply offer guarantees about what will happen, implementations *should* endeavor to make such guarantees available to the programmer. – supercat Feb 16 '16 at 19:19
9

I found few example, quoting of ECMAScript Language Specification (emphasis mine):

8.5 The Number Type

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.

15.7.4.5 Number.prototype.toFixed (fractionDigits)

If the toFixed method is called with more than one argument, then the behaviour is undefined (see clause 15).

15.7.4.6 Number.prototype.toExponential (fractionDigits)

If the toExponential method is called with more than one argument, then the behaviour is undefined (see clause 15).

15.7.4.7 Number.prototype.toPrecision (precision)

If the toPrecision method is called with more than one argument, then the behaviour is undefined (see clause 15).

15.9.4.3 Date.UTC (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )

When the UTC function is called with fewer than two arguments, the behaviour is implementation-dependent.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 4
    I think the first example is not valid, since *to ECMAScript code all NaN values are indistinguishable from each other*. I'm sure in nearly every language external code might be able to detect implementation-differences not covered by the language spec. – Bergi Feb 13 '13 at 21:58
6

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.

Niko
  • 26,516
  • 9
  • 93
  • 110
hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
3

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.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

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).

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • I don't think the Standard specifies *any* situation where a conforming implementation would be required to do *anything* without crashing, is there? I don't think the Standard's failure to forbid implementations from crashing when code performs some action is intended to imply any "special" license to crash in such cases. – supercat May 31 '19 at 15:30