Saturday, February 7

Safari 3.2.1 bug: Random unicode characters munged into select drop down

I recently encountered a very bizarre browser bug involving a <select> drop down in Safari 3.2.1.

Changing the selection was resulting in random characters overwriting the text contents of the selected <option> element.

Since this behaviour wasn't happening in the latest version of WebKit, my bug report was resolved WORKSFORME.

This wasn't particularly helpful as I still needed to figure out a workaround for a bug that was affecting people using the current shipping version of Safari.

I eventually managed to isolate a minimal test case here:
http://james.wheare.org/stuff/bugs/safari/fixedselect

The setup looks like this:
<div id="relative" style="position: relative;">
<div id="fixed" style="position: fixed; top: 0; left: 0;">
<select>
<option>Choose another option</option>
<option>Garbled</option>
</select>
</div>
</div>
The bug is triggered by javascript:
// Set the fixed container's positioning to absolute
var element = document.getElementById('fixed');
element.style.position = 'absolute';
// Access its clientWidth or clientHeight properties
element.clientWidth;
element.clientHeight;
// Restore the positioning to its original value of fixed
element.style.position = 'fixed';

Now, just select a different option from the drop down and it's text content will be munged with random characters.

This may seem like quite a strange sequence of operations but it's actually used in the Prototype library's Element.getDimensions method [source].

When I discovered this bug, it was additionally causing Safari to crash if you continued to use the drop down. This test case doesn't trigger the crash, but it's almost certainly the same root cause.

There a few options to workaround this issue, depending on your particular situation:
  1. Avoid Element.getDimensions.
  2. Modify Prototype's Element.getDimensions function.
  3. Change the positioning of your containers.
  4. Wrap the select in another position: fixed element and don't call Element.getDimensions on it.
  5. Wait for Apple to release a new version of Safari.

If you choose to modify Element.getDimensions, there's a handy way to do that without altering the Prototype source code. Simply define your own version and then extend Element with it by using Element.addMethods. This will override the built in method.
Element.addMethods({
getDimensions: function(element) {
// Your version in here
// ...

}
});

If you're wondering how to patch Element.getDimensions, I forked Prototype on github with a fix for this issue:
Fix for Element.getDimensions

I also filed a ticket for Prototype to add a fix for this themselves:
Element.getDimensions causes issues in certain conditions in Safari
Update: This fix has been accepted into Prototype and should make its way into a future release.

Labels: , , , ,