A very localized bug indeed

I found the nastiest bug the other day. I’m working on a small piece of code that will live inside ads made with Flash and reports some stats like the size and position on the page. I discovered that under some very localized conditions my code would make Safari crash. Hard.

I managed to track down the error to a JavaScript call (by way of ExternalInterface) that determined the position of the ad on the page. It crashed Safari 3 with Flash Player 10 if the ad was embedded in an object tag and compiled as ActionScript 2. It didn’t crash with Flash Player 9, and it didn’t crash if the ad was embedded with just an embed tag, nor if the object tag didn’t have an id attribute (but it has to have, for reasons I will get to), and the equivalent code compiled as ActionScript 3 ran fine.

The weirdest thing was that it didn’t crash straight away, it crashed only once the JavaScript had returned, and Flash Player was done with its current frame. The exact JavaScript code that made the difference between crash and non-crash was element.offsetParent, but again, this didn’t crash the browser when it ran, but made the browser crash once the JavaScript and Flash execution was done. The exact reason for the crash was EXC_BAD_ACCESS somewhere in the interface between Safari and the Flash Player plugin, judging from the crash logs.

I had no idea how to solve it. It’s a very specific set of parameters: Safari, Flash Player 10, embed with an object tag, but there’s nothing in that list that hints to the cause.

Finally, yesterday I solved it. Not by understanding why these conditions were significant, but by removing an unnecessary and more or less unrelated line of code. It turns out that setting the display of an object node and then just after querying it’s offsetParent property from Flash Player 10 makes Safari do ugly things.

This is the code that causes the crash:

ExternalInterface.call("function(id){ ¬
  document.getElementById(id).style.display='block';}", ¬
  objectId);

var pos = ExternalInterface.call("function(id){ ¬
  var x=0,y=0;
  var elem=document.embeds[id]||document.getElementById(id); ¬
  while(elem){ ¬
  x+=elem.offsetLeft; ¬
  y+=elem.offsetTop; ¬
  elem=elem.offsetParent;} ¬
  return [x,y]}", ¬
  objectId);

Code reformatted for a little bit of extra clarity, it’s not easy to get code readable when it’s embedded as a string in another language. The ¬ denotes lines that have been artificially broken.

When I uncommented the elem=elem.offsetParent part (and the loop, obviously) there was no crash, so I’m pretty sure that was the culprit.

However, when I removed the first call, the one that sets the display style to "block", there was no crash even with the line I had previously had to comment out. So the combination of setting display='block' and querying an elements offsetParent crashes Safari, but only if the code is called from Flash Player 10. Do the same in Flash Player 9 and it runs fine, call the same code from the HTML page instead from inside the ad and it runs fine, compile it as ActionScript 3 (with the necessary modifications) it runs fine. Really, really, frustrating, strange and annoying.

It was pure accident that I found that if I removed the code that set the display style it worked fine, and even luckier that that code wasn’t really necessary anyway (it was just a workaround for if the ad was embedded with align set to "middle", which they never are anyway.

You may have noticed the objectId variable passed as an argument to ExternalInterface.call. That’s another annoyance I’ve had to deal with this week. Since I’m stuck with ActionScript 2 (because no internet ad agencies use ActionScript 3 yet, and most actually use ActionScript 1) I don’t have any way to get to the ID of the node that is the embedded ad. In ActionScript 2 there is, to the best of my knowledge, no equivalent of ExternalInterface.objectID, which isn’t the easiest thing to work around — and you really need the ID otherwise you can’t do things like finding the position on the page, because that requires you to know which node to start from. Anyway, that’s a different story.

This was probably not the most interesting blog post I’ve written for this blog, but I just had to get it out of my system, and besides, perhaps someone has the same problem someday and finds my ramblings and manages to solve their problem, who knows.

6 Responses to “A very localized bug indeed”

  1. TK Says:

    I just ran into a similar bug with Flash Player last week. Any dynamic resizing of Flash Player at runtime in a browser which is initiated by Flash Player through an ExternalInterface call will cause Firefox to immediately crash 90% of the time.

    Adobe really needs to get their crap straight with browser interaction. I had to create an application using frames, and any resizing of Flash Player will cause the browser to crash, even if it’s caused by a manual user-driven resize of the browser.

    http://bugs.adobe.com/jira/browse/FP-17

  2. Theo Says:

    I’m both happy and sad that I’m not alone in seeing these kinds of bugs =)

  3. Jensa Says:

    Strange bug. I wonder who would blame who if the Safari and Flash Player engineers discussed this one :)

    I had a similar experience last week as well – very much an edge case that involved IE6 and loading XML. I also just wrote about it for future reference: http://www.flashgamer.com/2009/02/flash_and_ie6_bug_when_loading.html

    J

  4. jared Says:

    Well i’m a C++ developer and i have an app that host an embedded flash control (activex) and i’m getting a crash from flash 10 (flash 9 is fine) when I try to resize the activex control from C++ code . everything is fine as you say until the next frame the flash player tries to render.

    I’m guessing my code is acting very much like the browser would when resizing the control.

  5. t-|-| Says:

    Flash Player 10 Debugging Version seems a lot more buggy than the standard player for me. I’ve tried IE7/8, Fx3.5, Opera 10…

  6. spender Says:

    You might be interested in reading a rant I had about this:

    http://www.flexiblefactory.co.uk/flexible/?p=123

Leave a Reply