The reality of the situation is that 10% of users jailbreak their device. It is not reasonable to ban all of these people from leaving reviews in the App Store.

That said, I am very curious what this bug was that caused "broken shadows". There are an insane number of heavily varied modifications available in Cydia, and I don't even claim to know what even most of them are, but I'm seriously dying to know what kind of change would have caused behavior like that.

In my experience (yes: I sometimes reverse engineer the developer's app, find the bug in their code, and send them a "pseudo-patch" when they get uppity enough ;P), almost every single case of a developer making claims about bugs specific to jailbroken devices actually had a "root cause" of "memory allocation bug in original application triggered by slightly different malloc order".

To further explain what this kind of bug is, this is where the application ends up having a corrupted or obsolete pointer to some other object due to some very serious issue.

A very simple example is just "released an object, but did not clear the pointer to it, and ended up continuing to use the object later". In this situation, the pointer usually ends up not just pointing to garbage: a later object allocation reuses that memory, and due to alignment often ends up at the exact same address.

Of course, the cause can be more indirect: once in this scenario, you might accidentally run the release logic again, only now the release message (or call to free) ends up affecting the /new/ object, causing pointers to /that/ object to become stale, which in turn causes them to point to a further new object. ;P

In this scenario, testing the application may simply "work": the objects may not be used all that often, and the ramifications may be something mostly benign (new also mostly useless objects are always created anew within enough time to make the pointers keep sort of working).

Yet, there is still a bug here, and it may be triggered at any time: if the order of memory allocation and deallocation in other parts of the codebase change slightly, then these stale pointers may end up pointing at something "less benign": maybe you end up freeing the entire shadow of the character, for example, rather than just the word balloons that are constantly being reallocated at different positions anyway.

This kind of thing makes you feel safe if you only test on a single system: you tell yourself that the user's device is going to work the same as yours, and that there is no way you are going to have plenty of time to fix these errors in production if they ever occur.

...of course, unless those bastard jailbreakers do something stupid to your process, breaking your app.

In reality, however, you don't, for a very important reason: deep library code is also using the same memory heap, and you do not get ahead warning of these changes, as Apple (rightfully) does not believe you need to know about them.

When new devices come out, which to date have been heavily correlated with new versions of iOS, they are not running "the gold master" build of the OS: instead they have random changes strewn throughout, and usually have a different build number (despite having the same firmware version).

Sometimes the difference is quite dramatic, though, like with the Verizon iPhone, which came out with a bang: complete access to the App Store with a massively different version of AppSupport (or whatever the moral equivalent is these days), a key library used by UIKit.

You can get really subtle changes like this, however: when 4.3.5 came out, the SSL routines for verifying certificates had to become more complex, and this was released with no notice to developers and only a week of testing even internally at Apple. There is no reason why a change like this couldn't cause changes in dynamic memory ordering.

Now, you might ask "how do we debug stuff like this"? You could wait for your app to crash in the field, but preferably you are debugging this as you write the code. Clang is trying to help, as are specific new features of Xcode 4 built on it, but static analysis can only catch so much.

At the Objective-C level, there is a feature called NSZombie you can use to help debug stale pointer references (no memory is deallocated: it is simply replaced with an NSZombie; a class that is not allowed to receive any messages without terminating the program and logging a stack trace), but at the C level you are on your own.

However, one great way to test stuff like this, is to get a jailbroken device, install a bunch of sketchy hacks on it (preferably the ones that I personally claim are "dangerous and should be used by no one", bonus points if you can find one where "the developer should be ashamed of himself" ;P), and then see if your app keeps working.

If you aren't doing this, you are going to get burned one day by a normal upgrade: you are taking a risk, and to save something that probably will just take an hour of your time, and will improve your codebase because of it.