Blog


Most Bizarre IE Quirk

I was playing around with timers the other day, trying to see how different browsers handled different edge cases, when I stumbled across a fascinatingly bizarre quirk in Internet Explorer. I wouldn't call it a bug, per se, since that would imply that there was an excepted result, but there is not. The code:

setInterval(function(){
    alert("hello!");
}, -1);

Now, before you view the demo (view in IE only!) try to guess what the above code does.

Since -1 isn't a valid interval my guess was that it would, either (based upon Internet Explorer's current setInterval behavior):

  1. Execute immediately, like a normal function, but then never fire again.
  2. or not execute at all.

What happened is positively bizarre: The callback function will be executed every time the user left clicks the mouse, anywhere in the document.

I find this to be absolutely hilarious. I'm struggling to think of how this could, possibly, be used in any remotely feasible way. Some random ideas:

  • A global click handler that can't be removed and doesn't leak memory (presumably since no DOM elements involved?)
  • Some sort of vector for XSS attacks. I don't know what the situation would be where you have access to setInterval but not the DOM, so I'm not sure what credence this has.
  • A way to initiate a fake event capturing click event (before the actual bubbling event occurs).

I don't know - I'm not sure if any of them are terribly useful but I find it to be amusing nonetheless. Thoughts on how we can have fun with this?

Tags: bugs, javascript, browsers

Acid 3 Tackles ECMAScript

Update: The Acid3 test is now final, I've updated the blog post to reflect this.

The new news on the block is that the upcoming Acid 3 test is in the oven, starting to get baked. Traditionally, the Acid test has served as a way to get browser vendors in line by testing them on really-annoying edge cases. This can, sometimes, get people tied up in knots but it actually serves as a devious way of getting people to meet a large part of a spec.

For example, in order for a browser to have some weird padding/margin test case solved - in CSS - they must also have a working box model. So while an Acid test may not, explicitly, test for a working box model, it will be done implicitly (by testing edge cases that result from it).

With that in mind, it's time to take a look at Acid 3 which primarily focuses on technology that I find to be interesting: ECMAScript and the DOM. Let's dig in and see what exactly is being tested - specifically, relating to ECMAScript.

  • Array Elisions - Making sure that stuff like [,,] has a length of 2 and [0,,1] has a length of 3.
  • Array Methods - Doing an unshift with multiple arguments .unshift(0, 1, 2), joining with an undefined argument .join(undefined).
  • Number Conversion - Banging against .toFixed(), .toExponential(), and .toPrecision() - especially with decimals and negative numbers.
  • String Operations - Negative indicies in substr .substr(-7, 3), character access by index "foo"[1] (part of the ECMAScript 4 spec).
  • Date - Making sure that certain method calls result in NaN results (like d.setMilliseconds(), with no arguments) and also enforcing +1900 year offsets.
  • Unicode in Identifiers - You can't use escaped Unicode in identifiers, for example: eval("test.i\\u002b= 1;"); (that should throw an exception).
  • Regular Expressions - /[]/ matches an empty set, /[])]/ should throw an exception, backreferences to non-existent captures, and negative lookaheads /(?!test)(test).exec("test test").
  • Enumeration - Make sure that object properties are enumerated in the correct order, make sure that you're able to enumerate properties of certain names (toString, hasOwnProperty, etc.).
  • Function Constructors - The user should be able to set custom constructors on the .constructor property, .constructor should not be enumerable, and .prototype.constructor should be deletable.
  • Function Expressions - (function test(){ ... })(); You should be able to call the function by name, within the function itself, you can't directly overwrite the function name (only with a function-scoped variable), and 'test' isn't leaked into the parent scope.
  • Exception Scope - Variables within the catch(){} should interact with the catch arguments primarily, followed by variables in an outer scope.
  • Assignment Expressions - s = a.length = "123"; - a.length has a return value of 123 (the number) which is assigned to 's', rather than the correct result of the string "123".
  • Encoding - encodeURI() and encodeURIComponent() must gracefully handle null bytes.

All-in-all it's a comprehensive smattering of weird ECMAScript edge cases - you're bound to find at least one that fails in your favorite browser-of-choice. I'm sure we'll see many more test cases coming in, in the upcoming days in weeks.

I'm looking forward to seeing the final results - and the competitive heat that's been applied to CSS-spec implementors being applied to ECMAScript implementors.

For kicks, here's the current results in a bunch of major browsers (including the correct reference rendering).

These are the preliminary results of the UNCOMPLETED Acid 3 test in UNCOMPLETED versions of major browsers - take with a grain of salt. Go here to view the final version of this test.

Reference Rendering:

Firefox 2:

Firefox 3b2:

Safari 3:

WebKit Nightly:

Opera 9.5b1:

Internet Explorer 7: (thanks chunghe!)

Tags: testing, ecmascript, bugs

Object getElementsByTagName IE7 Bug

So here's a fun bug to keep you entertained this weekend. Personally, this is the first purely-JavaScript bug that I've seen in IE7 (More due to the lack of anything changing than the quality of the code.)

Summary:
When accessing the .all or .getElementsByTagName("*") properties on the DOM representation of an <object> element, the resulting NodeSet will always be empty.

Proof of Concept:
HTML:

<object>
  <param name="name" value="value"/>
  <param name="name2" value="value2"/>
  <param name="name3" value="value3"/>
</object>

JavaScript:

var obj = document.getElementsByTagName("object")[0];
// => <object/>
obj.all
// => []
obj.getElementsByTagName("*")
// => []
obj.getElementsByTagName("param")
// => [ <param/>, <param/>, <param/> ]
obj.firstChild
// => <param/>
 

Andrea has done some fantastic work in tracking this bug down and providing a fix for it.

So far, my quick-and-dirty kludge is just to replace "*" with "param" and hope that the user is actually using an object to hold params, and not some other crazy combination.

Which reminds me - has anyone ever seen an example of an <object> element containing non-param elements on a real, live, web page - somewhere in the wild? The HTML spec says that the <object> element can contain any HTML, but that sounds a little bit too crazy for my tastes.

Tags: ie7, browsers, bugs, object, getelementsbytagname

Serious Greasemonkey Security Problems

If you haven't been keeping up on the recent security concerns with Greasemonkey - now's a good time to jump in. I had no idea that the problems where 'that bad' until today. I assumed that it was only possible to do something malicious within a user script, not outside of it (due to bad scoping issues). At least, until, this post caught my eye.

Uninstall Greasemonkey altogether. At this point, I don't trust having it on my computer at all. I would think that whoever is in charge of addons.mozilla.org should immediately remove the Greasemonkey XPI and post a large warning in its place advising people to uninstall it. --Mark

Backtracking through the entire security thread brings up quite a few serious problems. Currently, it's possible to do the following things:

Do not fear! - Headway is already being made. The main concern is that it's possible to access all of the above data outside of a user script's scope. Once this is resolved (and the afformentioned hack may just do that) then Greasemonkey will be back on the fast-track.

Tags: bugs, greasemonkey, firefox, extensions, security

IE DOM/DHTML Bugs

During the re-write of the Schedule Maker, I've encountered a number of 'issues' that exist when developing cross-browser web applications, mainly in Internet Explorer. I'll point out a couple important ones here:

  • document.createElement()
    - This command works as advertised in both IE and Firefox, with one notable exception - if you create an element that is not part of the HTML spec, you cannot access the normal DOM functions. Specifically, the code looked something like this:
    var d = document.createElement(\"data\"); d.appendChild( elem );

    To which, Internet Explorer complains stating that the method is not supported.
  • xmlDoc.getElementById()
    - When importing XML from an outside source, using XMLHTTPRequest, IDs may not be properly assigned to the elements. According to the XML spec, in order to specify an ID you have to include a DOCTYPE that specifies it as such. However, it appears as if IE even ignores this. Instead, I just rolled my own getById() function to handle the request. Obviously, this is less then ideal, but the number of ID requests that I make was minimal, making this 'not that bad'.
    CDATA:
    <!DOCTYPE data [<!ATTLIST course id ID #IMPLIED>]>

    getById() Function:
    function getById( obj, name ) {   return getByTypeId( obj, \"*\", name ); }  function getByTypeId( obj, type, name ) {   var c = obj.getElementsByTagName( type );   for ( var i = 0; i < c.length; i++ ) {     if ( c[i].getAttribute(\"id\") != null && c[i].getAttribute(\"id\") == name )       return c[i].cloneNode( true );   }   return null; }

I'm not sure if these error stem from actual bugs in the browser or if they're programming errors, but I fought them for hours and have grown to hate their existance.

Tags: browsers, browsers:ie, bugs, javascript

Current Projects

jQuery JavaScript Library

jQuery

Comprehensive DOM, Event, Animation, and Ajax JavaScript Library.

Recent Projects

Pro JavaScript Techniques

JavaScript Book

The best techniques for professional JavaScript. Published by Apress.


Hosting provided by the cool dudes at Engine Yard.