Bug 7751 - Scope is broken with nested evals inside of functions.
Summary: Scope is broken with nested evals inside of functions.
Status: RESOLVED INVALID
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 420+
Hardware: Mac OS X 10.4
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-03-13 05:10 PST by Francisco Tolmasky
Modified: 2007-07-14 12:42 PDT (History)
3 users (show)

See Also:


Attachments
Breaks scope. (341 bytes, text/html)
2006-03-13 05:13 PST, Francisco Tolmasky
no flags Details
Reduced Test Case (117 bytes, text/html)
2006-03-17 11:06 PST, Francisco Tolmasky
no flags Details
Fixed Reduced Test Case (115 bytes, text/html)
2006-03-18 20:58 PST, Francisco Tolmasky
no flags Details
Further reduced test case (138 bytes, text/html)
2007-07-11 03:03 PDT, Cameron Zwarich (cpst)
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Francisco Tolmasky 2006-03-13 05:10:01 PST
When I nest evals, even though I do eval.apply(window, ...) the this object is kind of window and kind of not.  Doing alert(this==window) alerts true, however doing function a() { } will not put a into this, or window for that matter.  Check the attachment for a clearer example.  Note, this works fine in Firefox.
Comment 1 Francisco Tolmasky 2006-03-13 05:13:48 PST
Created attachment 7046 [details]
Breaks scope.

We should be seeing this alerted:

yup!
[Object Window]
function a() ...
function a() ...
function a() ...
true
Bluebird of happiness

(run it through firefox, it will gives this result).
However, we instead get this:

yup!
[Obejct Window]
undefined
function a()...
undefined
true
Bluebird of happiness

The strange thing is that "this" really thinks its window, but it doesn't behave like it since a() doesnt get registered into window.

If you comment out the r function, so that everything that happens is global, like this:

<script>

alert("yup!");

//function r()
//{
    var predefined_js= "alert(this);function a(){alert('bluebird of happiness');}alert(this.a);alert(a);alert(window.a);alert(this===window);";
    var main_js= "eval.apply(window, [predefined_js]); main= function() { a(); return 0; }";

    eval.apply(window, [main_js]);
//}

//r();

main();

</script>

Now it works as it should.
Comment 2 Francisco Tolmasky 2006-03-17 11:06:52 PST
Created attachment 7136 [details]
Reduced Test Case

The function internals should be outputted.
I believe what's happening is that if the scope is not 100% "shallow" it refuses to allow declarations of type function [name] { } to be added to the global object.
Comment 3 Francisco Tolmasky 2006-03-18 20:58:24 PST
Created attachment 7168 [details]
Fixed Reduced Test Case
Comment 4 Cameron Zwarich (cpst) 2007-07-11 03:03:30 PDT
Created attachment 15472 [details]
Further reduced test case

(In reply to comment #2)

> I believe what's happening is that if the scope is not 100% "shallow" it
> refuses to allow declarations of type function [name] { } to be added to the
> global object.

It also happens for other declarations, and for single evals, not just nested evals. I simplified your original example a bit to get the attached test case. In Firefox and Opera it outputs "bluebird of happiness" three times, but in WebKit it outputs "undefined" instead of the first.

However, I don't think this is actually a bug. I think Safari has the correct behaviour here, judging by the ECMA spec. I will explain my argument.

In the spec (chapter 10, although most of what I am saying comes from section 10.2), there are a few important pieces of context-sensitive information. The two that affect the situation in this bug report are the variable instantiation context and the value of "this".

According to 10.2.3, when you call a function without specifying the "this" value, it is inherited from the caller. Thus, in my example, the value of "this" in the function body of f() the only time it is called is the global object. The variable instantiation context is, of course, local to the function and is not the same as the global variable instantiation context.

According to 10.2.2, for code run by using eval, the variable instantiation context and the "this" value are inherited from the caller. If you take my attached example and change "eval.call(this, " to simply "eval(", all three major Mac browsers agree (I couldn't test IE) that it should output "undefined" and then "bluebird of happiness" two times.

So, what is different when you use eval.call (or eval.apply) that causes the other browsers to behave differently? First, note that 10.2.2 seems to imply that evaluated code always has a "this" object of its calling context, although that isn't the issue here, as all of the browsers agree on what the "this" object should be. However, they disagree on what the variable instantiation context should be. Firefox and Opera think that by passing "this" as the first argument of call, the variable instantiation context of the evaluated code changes to the top level. But 10.2.2 says that the variable instantiation context is always that of the caller and is not dependent on the value of "this". And according to 15.3.4.4, passing something as the first argument of call could only possibly change the value of "this". Therefore, WebKit's behaviour seems to be correct.
Comment 5 David Kilzer (:ddkilzer) 2007-07-11 21:33:57 PDT
See also: http://bugs.webkit.org/show_bug.cgi?id=12912#c6
Comment 6 Cameron Zwarich (cpst) 2007-07-12 00:17:18 PDT
I went to file this as a bug in the Mozilla Core Bugzilla. But first I figured I'd have the etiquette to test it on a newer build, so I downloaded Firefox 3.0a7pre. Surprisingly, it now has the same behaviour as Webkit. I searched the Bugzilla for a bug report and I couldn't find one. If I am really bored, I will hunt down the change in Firefox, but I am not that familiar with their codebase.

The Firefox 3.0 alpha also affects the behaviour mentioned in bug 11399, making it the same as Webkit. I will make a separate comment there.

Perhaps someone should review this bug and mark it INVALID?
Comment 7 David Kilzer (:ddkilzer) 2007-07-14 12:42:47 PDT
Marking as RESOLVED/INVALID per Comment #4 and Comment #6.