archives

« Bugzilla Issues Index

#23 — S15.5.4.10_A1_T3 asserting incorrect behavior


S15.5.4.10_A1_T3 Checking by using eval
function testcase() {
var match = String.prototype.match;
if (typeof toString === "undefined") {
toString = Object.prototype.toString;
}
var __class__ = toString();
if (match(eval("\"bj\""))[0] !== "bj") {
$ERROR("#1: match = String.prototype.match;
match(eval(\"\\\"bj\\\"\"))[0] === \"bj\". Actual: " +
match(eval("\"bj\""))[0]);
}
}

It seems like the four lines to do with __class__ are irrelevant and can just be deleted.

More importantly, when match is called, step 1 in 15.5.4.10 requires that it throw a TypeError, because the this-value is undefined. But the test expects the call to succeed and return an array.


Agree that line 17 "var __class__ = ..." can and should be removed.

I'm not so convinced about the argument about 15.5.4.10 step 1 making this invalid though. Line 11 equates to:
this.match = String.prototype.match;
and lines 13-14:
this.toString = this.toString || Object.prototype.toString;

when match is called, won't 'this' be set to the global object (by 10.4.3 step 2)? If so, the CheckObjectCoercible call won't throw.

All this said, the test still seems invalid as the check on line 13 is making a pretty strong assumption about the the host object's toString method if it exists. That is, the result will contain the substring "Object". While I'd buy this is the case for (all?) built-in objects defined in ES5, it doesn't seem to be a sure thing for host objects...

If you agree with this assessment, please let me know and I'll disable the test as invalid.

Thanks,

Dave


(In reply to comment #1)
> when match is called, won't 'this' be set to the global object (by 10.4.3 step
> 2)? If so, the CheckObjectCoercible call won't throw.

This is a change from ES3.

10.4.3 only applies to functions that create an execution context. Functions written in ES5 all have the same [[Call]] method (13.2 step 6) and it creates an execution context (13.2.1 step 1; note that step 2 is not suitable for built-in functions, so this [[Call]] method clearly is not the one built-in functions use). Built-in functions don't. Their [[Call]] and [[Construct]] methods do exactly what their spec says. If they want "this" to be an object, they have to coerce it themselves.

That's why the call to CheckObjectCoercible is there in the first place. Otherwise it would be useless.

It's also why so many built-in functions were changed in ES5 to have a step 1 that reads, "Let O be the result of calling ToObject passing the this value as the argument." That wasn't necessary in ES3, because the this value was always an object.

Annex E mentions this change too: "In particular, in Edition 5 built-in functions that are specified to actually use the passed this value as an object typically throw a TypeError exception if passed null or undefined as the this value."


Never mentioned it in this bug report, but the test case was disabled;)


I've fixed the test by binding match's this to fnGlobalObject() and only asserting when we can use Object.prototype.toString for the global object's toString method:
var match = String.prototype.match.bind(fnGlobalObject());
try {
fnGlobalObject().toString = Object.prototype.toString;
} catch (e) { ; }

if ( (fnGlobalObject().toString === Object.prototype.toString) &&
(match(eval("\"bj\""))[0] !== "bj")) {
$ERROR('...');
}