Friday, November 30th, 2007

Bug: Object Killing in IE7

Category: JavaScript

<>p>Jon Sykes thinks he has found a bizarre bug in IE7. Since Microsoft has 34 QA people per developer, surely not! ;)

He told us:

There is a bug in IE7 where by a line of code inside a conditional statement that NEVER runs, can cause an object that is set with a fairly standard object declaration to be whipped. Even weirder is that it will have whipped the code even if you put a debug alert of the object before the code that does the whipping. Confused? I know I am.

Thankfully it does look fairly simple to work _around_ and avoid. But it’s probably a debug nightmare, and it’s a bug I couldn’t find referenced anywhere, so I figured it was worth sharing.

A simple test case is:

  1. <script type="text/javascript">
  2.         this[‘test’] = {};
  3.         alert(this[‘test’]);
  4.         // will spit out [Object object]
  5. </script>
  6. <script type="text/javascript">
  7.          alert(this[‘test’]);
  8.          // will spit out Undefined in IE7
  9.  
  10.          // this next chunk of code should never run.
  11.          if (true == false){
  12.            alert("This never fires");
  13.            // THIS SHOULD NOT IMPACT ON ANYTHING !!!!
  14.            var test; // take this line out and it works fine
  15.            alert("This never fires");
  16.          }
  17. </script>

Related Content:

Posted by Dion Almaer at 2:16 am
20 Comments

++++-
4 rating from 28 votes

20 Comments »

Comments feed TrackBack URI

This… has to be the work of some asshole dev who got sick of hearing about how terrible IE is. And I’m sure QA wouldn’t catch it because who in the hell would ever test for that?

Comment by Trevor — November 30, 2007

The smart quotes are ruining the code.

Comment by AndyB — November 30, 2007

That comment about “should have no effect” isn’t exactly true. Remember that JavaScript doesn’t have block scope, it has function scope. So that var declaration takes effect at the start of the function that it’s running in. This means that “test” is a variable with the value undefined in that scope. Now to me it looks like IE7 is treating each script tag as it’s own function. I have no idea how correct or incorrect this is.

It’s also worth pointing out that jslint would have warned you about this behaviour.

Comment by happygiraffe — November 30, 2007

“So that var declaration takes effect at the start of the function that it’s running in.”

What? You mean the JS engine evaluates code within an if statement that evaluates false? And that’s “correct” behavior? Scope doesn’t enter into it, code that is in an if statement that evaluates false should never run.

Comment by Trevor — November 30, 2007

The JavaScript engine does not evaluate the the code. It just treats all variables, which are declared using “var” as local variable in the function they have been declared in. This happens while parsing the function and is independent of the fact whether the code will actually be executed.

One exception are variables, which are declared in the global scope (outside of any function). They are always global even if they are declared using “var”.

The strange thing about the example above, as happygiraffe pointed out, is just that IE seems to treat each script tag as it’s own function.

Comment by Fabian Jakobs — November 30, 2007

In JavaScript, we have two scopes: global and function. Let’s take the EcmaScript specifications, which could demonstrate that your code is buggy instead.

From 12.2 – Variable statement:

If the variable statement occurs inside a FunctionDeclaration, the variables are defined with function-local scope in that function, as described in s10.1.3. Otherwise, they are defined with global scope (that is, they are created as members of the global object, as described in 10.1.3) using property attributes.

In your case, “this” is “window”, the global scope. So, “var test” is the same as window['test'], or even this['test'].

Then, from the specs again:

Variables are created when the execution scope is entered.

Opps… it’s saying that all variables defined in the scope are created at the start of the code execution, not at the declaration point.

Now, right after it:

Variables are initialised to undefined when created. A variable with an Initialiser is assigned the value of its AssignmentExpression when the VariableStatement is executed, not when the variable is created.

Well… it sounds like IE’s behavior reflects the specs perfectly.

At first look, it stills sounds bizarre, but well… probably the bug is the script code instead.

Comment by FredCK — November 30, 2007

By that logic, the first alert should also spit out undefined.

Comment by Trevor — November 30, 2007

@Trevor: that’s is not exactly true. It is also known that each block is executed separately. The second runs like a new scope execution, which inherits all properties defined in the global scope from the first block.

Comment by FredCK — November 30, 2007

Weee :) I think there is no hope to have appropriate browser from Microsoft.

Comment by Serg — November 30, 2007

FredCK, your quotes from the spec prove that the “var” statement in the second script block rightly defines the variable (in the global context) although it is never reached. That is alright.

Now, the code in both script blocks has the global object as its execution context, right? The first block is parsed and executed, then the second block is parsed and executed, right?

In the first block, “test” is created. Now the second block executes. The “var” declaration should not have any effect (that is: not create and declare test as undefined), as “test” is already created.

Comment by Martin — November 30, 2007

FredCK:

If that’s true, wouldn’t that be a bug? As you said, “this” is “window”, the global scope. Is there a global scope for each script?

Comment by Trevor — November 30, 2007

@Martin: I think we found the buggy part of IE.

From EcmaScript specs 10.1.3 – Variable Instantiation:

For each VariableDeclaration or VariableDeclarationNoIn in the code, create a property of the variable object whose name is the Identifier in the VariableDeclaration or VariableDeclarationNoIn, whose value is undefined and whose attributes are determined by the type of code. If there is already a property of the variable object with the name of a declared variable, the value of the property and its attributes are not changed. Semantically, this step must follow the creation of the FormalParameterList and FunctionDeclaration properties. In particular, if a declared variable has the same name as a declared function or formal parameter, the variable declaration does not disturb the existing property.

Yes, you caught it!

@Trevis: I suppose you are running the code in a page in the browser. So yes, “this == window == global scope”, and this global scope is certainly shared by all scripts running in that window.

Comment by FredCK — November 30, 2007

I feel like this is something I should get why we’d need to do this…. but I don’t. I hold similar regards to comment #1
- “… who in the hell would ever test for that?”

Comment by Dustin Diaz — November 30, 2007

@Dustin: you are right… probably just bad code would face this problem. But you know… it’s always nice to understand why things happen… you always learn something from it.

Maybe next time I’ll spend my time with the Big Bang instead :) or even better… coding!

Comment by FredCK — November 30, 2007

I saw some code …(In visual Basic) with
if 1==2..
so it wouldn’t surprise me to see people write code like that..

Comment by Rodrigo — November 30, 2007

The situation came up because we’re adding Dojo to a legacy system.

The legacy system had script blocks that did an object check before creating the object:

if(typeof objectName != undefined){
objectName = {};
}

Throw in a Dojo provide before that and suddenly you’ve got vanishing objects all through your system.

I’m still confused why doing:

var test = {};

instead of

this['test'] = {};

Solves the problem. That seems to fly in the face of the ascertain that what it’s doing is correct. That said the quoted stuff above is very interesting, and opens a whole new light on it.

Comment by JP — November 30, 2007

var test = {}; probably works because the script engine now properly (internally) marks test as existent in the global scope, whereas this[‘test‘] = {} also creates the variable in the global scope but does not mark it properly. Or something like that. It is the inner working of the script engine that contains the bug, not your code.

Comment by Martin — November 30, 2007

Just to add to the discussion, each script block must be parsed and executed separately, and they cannot all be parsed together and then executed together, because the execution of one script block may affect whether or not the next script block runs. For example, imagine a scenario where the first script block uses document.write() to write out a comment (

Comment by Jordan — November 30, 2007

… and the comment causes the remaining script blocks to be commented out and thus invalid.

Comment by Jordan — November 30, 2007

Who the hell is this sitesmart person that keeps posting soft spam in the comments?

Comment by Dustin Diaz — November 30, 2007

Leave a comment

You must be logged in to post a comment.