archives

« Bugzilla Issues Index

#294 — ch15/15.3/15.3.5/15.3.5.4/15.3.5.4_2-95gs depends on implementation-defined behavior


ch15/15.3/15.3.5/15.3.5.4/15.3.5.4_2-95gs expects TypeError thrown.
description is below

@description Strict mode - checking access to strict function caller from non-strict, constructor-based function (FunctionDeclaration includes strict directive prologue)

According to ECMA262 5.1 section 15.3.2.1-9
If body is strict mode code (see 10.1.1) then let strict be true, else let strict be false

and 15.3.2.1-11
Return a new Function object created as specified in 13.2 passing P as the FormalParameterListopt and body as the FunctionBody. Pass in the Global Environment as the Scope parameter and strict as the Strict flag.

So, created function from `Function("return gNonStrict.caller;")` is always non-strict function even if global code is strict code.

And according to the section 13.2 Creating Function Objects, step 19

If Strict is true, then
Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.

So if function is non-strict code, function.caller can be undefined. (Function.caller is non-standard https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller)

Then, 15.3.5.4, [[Get]] step 2
If P is "caller" and v is a strict mode Function object, throw a TypeError exception.

It is implementation dependent that v is function object, so this test depends implementation-dependent.


Allen, the following code snippet is expected to throw a TypeError by the test:
var gNonStrict = Function("return gNonStrict.caller;");

function f() {
"use strict";
return gNonStrict();
}
f();


The relevant ES5 algorithm is:
1. Let v be the result of calling the default [[Get]] internal method (8.12.3) on F passing P as the property name argument.
2. If P is "caller" and v is a strict mode Function object, throw a TypeError exception.
3. Return v.


My take is:
- function 'f' is clearly a strict mode function
- gNonStrict is not a strict mode function
- as far as 15.3.5.4 is concerned: P==="caller" && F==="gNonStrict" => v===f
- v is indeed a strict mode Function Object. I.e., it being accessed from non-strict code doesn't change the fact that 'f' is strict => TypeError is thrown


Most of the tests in ch15/15.3/15.3.5/15.3.5.4 rely on implementations providing the non-standard "caller" property for non-strict functions. This is wrong to begin with. Therefore the tests need to be updated to cope with implementations which don't provide "caller" at all, similar to the suggested fix in bug 288.


> - gNonStrict is not a strict mode function
> - as far as 15.3.5.4 is concerned: P==="caller" && F==="gNonStrict" => v===f
> - v is indeed a strict mode Function Object. I.e., it being accessed from

The key point is that, because function.caller property of non-strict function is implementation-dependent behavior, v is allowed to be undefined by spec. v !== f.

> Therefore the tests need to be updated to cope with implementations which don't provide "caller" at all, similar to the suggested fix in bug 288.
Agreed.


I've just sent a mail to es5-discuss concerning 15.3.5.4, maybe the whole issue will get a wider attention there.


I'm dyslexic today. Do you agree the following generic change would alleviate the "Function.caller's not implemented" issue for the test cases expected to throw type errors:
var gNonStrict = Function("return gNonStrict.caller || gNonStrict.caller.shouldThrowTypeError;");

function f() {
"use strict";
return gNonStrict();
}
f();

Even with this change I think it belongs in the best practices directory (at best;) ). Thanks for spotting this!


> Do you agree the following generic change would alleviate
> the "Function.caller's not implemented" issue for the test cases expected to
> throw type errors:

I agree to this change, `Function("return gNonStrict.caller || gNonStrict.caller.shouldThrowTypeError;")` :-)
Thanks for your work and test262!


The change '||
gNonStrict.caller.shouldThrowTypeError;");' change has been checked-in. Still think that minimally the following might not be strictly required by ES5.1:
15.3.5.4_2-10gs Strict mode - checking access to strict function caller from non-strict function (New'ed Function constructor includes strict directive prologue)
15.3.5.4_2-16gs Strict mode - checking access to strict function caller from non-strict function (New'ed object from FunctionDeclaration includes strict directive prologue)
15.3.5.4_2-18gs Strict mode - checking access to strict function caller from non-strict function (New'ed object from FunctionExpression includes strict directive prologue)
15.3.5.4_2-20gs Strict mode - checking access to strict function caller from non-strict function (New'ed object from Anonymous FunctionExpression includes strict directive prologue)
15.3.5.4_2-2gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration includes strict directive prologue)
15.3.5.4_2-30gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration defined within a FunctionDeclaration with a strict directive prologue)
15.3.5.4_2-31gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression defined within a FunctionDeclaration with a strict directive prologue)
15.3.5.4_2-32gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression defined within a FunctionDeclaration with a strict directive prologue)
15.3.5.4_2-33gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration defined within a FunctionExpression with a strict directive prologue)
15.3.5.4_2-34gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression defined within a FunctionExpression with a strict directive prologue)
15.3.5.4_2-35gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression defined within a FunctionExpression with a strict directive prologue)
15.3.5.4_2-36gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration defined within an Anonymous FunctionExpression with a strict directive prologue)
15.3.5.4_2-37gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression defined within an Anonymous FunctionExpression with a strict directive prologue)
15.3.5.4_2-38gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression defined within an Anonymous FunctionExpression with a strict directive prologue)
15.3.5.4_2-39gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration with a strict directive prologue defined within a FunctionDeclaration)
15.3.5.4_2-40gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression with a strict directive prologue defined within a FunctionDeclaration)
15.3.5.4_2-41gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression with a strict directive prologue defined within a FunctionDeclaration)
15.3.5.4_2-42gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration with a strict directive prologue defined within a FunctionExpression)
15.3.5.4_2-43gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression with a strict directive prologue defined within a FunctionExpression)
15.3.5.4_2-44gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression with a strict directive prologue defined within a FunctionExpression)
15.3.5.4_2-45gs Strict mode - checking access to strict function caller from non-strict function (FunctionDeclaration with a strict directive prologue defined within an Anonymous FunctionExpression)
15.3.5.4_2-46gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression with a strict directive prologue defined within an Anonymous FunctionExpression)
15.3.5.4_2-47gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression with a strict directive prologue defined within an Anonymous FunctionExpression)
15.3.5.4_2-4gs Strict mode - checking access to strict function caller from non-strict function (FunctionExpression includes strict directive prologue)
15.3.5.4_2-53gs Strict mode - checking access to strict function caller from non-strict function (Injected getter includes strict directive prologue)
15.3.5.4_2-55gs Strict mode - checking access to strict function caller from non-strict function (Injected setter includes strict directive prologue)
15.3.5.4_2-56gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by non-strict function declaration)
15.3.5.4_2-57gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by non-strict eval)
15.3.5.4_2-58gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by non-strict Function constructor)
15.3.5.4_2-59gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by non-strict new'ed Function constructor)
15.3.5.4_2-60gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.apply())
15.3.5.4_2-61gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.apply(null))
15.3.5.4_2-62gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.apply(undefined))
15.3.5.4_2-63gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.apply(someObject))
15.3.5.4_2-64gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.apply(globalObject))
15.3.5.4_2-65gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.call())
15.3.5.4_2-66gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.call(null))
15.3.5.4_2-67gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.call(undefined))
15.3.5.4_2-68gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.call(someObject))
15.3.5.4_2-69gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.call(globalObject))
15.3.5.4_2-6gs Strict mode - checking access to strict function caller from non-strict function (Anonymous FunctionExpression includes strict directive prologue)
15.3.5.4_2-8gs Strict mode - checking access to strict function caller from non-strict function (Function constructor includes strict directive prologue)
15.3.5.4_2-94gs Strict mode - checking access to strict function caller from non-strict function expression (FunctionDeclaration includes strict directive prologue)
15.3.5.4_2-95gs Strict mode - checking access to strict function caller from non-strict, constructor-based function (FunctionDeclaration includes strict directive prologue)
15.3.5.4_2-96gs Strict mode - checking access to strict function caller from non-strict property (FunctionDeclaration includes strict directive prologue)
//--Maybe's
15.3.5.4_2-49gs Strict mode - checking access to strict function caller from non-strict function (Literal getter includes strict directive prologue)
15.3.5.4_2-51gs Strict mode - checking access to strict function caller from non-strict function (Literal setter includes strict directive prologue)
15.3.5.4_2-89gs Strict mode - checking access to strict function caller from non-strict function (non-strict function declaration called by strict Function.prototype.bind()())
15.3.5.4_2-70gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.bind()())
15.3.5.4_2-71gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.bind(null)())
15.3.5.4_2-72gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.bind(undefined)())
15.3.5.4_2-73gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.bind(someObject)())
15.3.5.4_2-74gs Strict mode - checking access to strict function caller from non-strict function (strict function declaration called by Function.prototype.bind(globalObject)())
15.3.5.4_2-90gs Strict mode - checking access to strict function caller from non-strict function (non-strict function declaration called by strict Function.prototype.bind(null)())
15.3.5.4_2-91gs Strict mode - checking access to strict function caller from non-strict function (non-strict function declaration called by strict Function.prototype.bind(undefined)())
15.3.5.4_2-92gs Strict mode - checking access to strict function caller from non-strict function (non-strict function declaration called by strict Function.prototype.bind(someObject)())
15.3.5.4_2-93gs Strict mode - checking access to strict function caller from non-strict function (non-strict function declaration called by strict Function.prototype.bind(globalObject)())
15.3.5.4_2-97gs Strict mode - checking access to strict function caller from bound non-strict function (FunctionDeclaration includes strict directive prologue)


15.3.5.4_2-96gs and 15.3.5.4_2-97gs need to be fixed as well


Good spot on 5.3.5.4_2-9(6|7)gs.js. These had eluded my RegExp Fu.

André, do you happen to know what was the final call on this category of tests from TC39? Standard, best practice, or invalid? Thanks!


On es5-discuss, everybody agreed that 15.3.5.4 itself is buggy since it redefines [[Get]] instead of [[GetOwnProperty]] and does not account for implementations without "caller" support (at least not in a reasonable way). But strictly speaking, no final decision was made concerning test262, mainly because the discussion was later focused on how to implement "caller".


Thanks for the update André. At this point I've verified all files still containing ".caller;" (i.e., "return gNonStrict.caller;") under ch15/15.3/15.3.5/15.3.5.4 fall into one of the following categories:
* they're subject to global strict mode and a TypeError is expected
* they're not subject to global strict mode and no TypeError is expected

Reassigning this as an ECMA-262 bug to get clear guidance whether any other test changes are still required due to the ES5.1 bugs.


See https://bugs.ecmascript.org/show_bug.cgi?id=3113


Bulk resolving ES5.1 errata issues as a sampling suggests these are all fixed. If this is in error, please open a new issue on GitHub.