Java Puzzle 3: Car - SolutionMar 04, 2012
Let's see how we can get the upgraded car to break the speed limit. Take a closer look at the car:
Lesson to all you racers out there: We want the car to accelerate a lot (
speed += acceleration must execute), but not do that thing where it hits the tree and comes to a full stop (
speed = 0 must not execute).
What can happen between those two statements? The
if (speed > MAX_SPEED) doesn't help us any further, because
speed really needs to be higher than
MAX_SPEED. So all that's left is the call to the
crash() method. That one has to fail: We want
crash() to crash!
We can do that by making sure there's not enough space left on the stack to be able to call any method. If the stack is almost full when we call
accelerate, we get a
StackOverflowError on the call to
crash(). How do we get the stack to be almost full? One way is to just brute-force it: an infinitely recursing method that just keeps trying.
And that works!... On some systems at least. A problem here is that if you're trying to accelerate so much and keep on crashing (after 1500 crashes on my system), the JVM does something no car maker ever would: it optimizes the car to ensure it can crash really fast. It in-lines the call to
crash(), reducing it to essentially
if (speed > MAX_SPEED) speed = 0;. That eliminates the possibility of a
We can work around that by being just a little gentler on the car: crash it a bit less, so the JVM doesn't decide to optimise that. First grow the stack until it's getting close to where it needs to be, and only then add the car into the equation. But the only way to know you're getting close to the limit is by hitting it. Therefor we recurse without the car until we hit the stack overflow, then take a few steps back, and then apply the brute-forcing solution from above:
An alternative solution is to use Thread.stop. But it's quite hard to time it right; it doesn't work that reliable across systems. At first I expected it to be impossible in practice, but I was proven wrong. You can see the code in the comments below.
You do need a special permission to call that method, but that's one of the very few things included in the default security policy file. The only other permissions in there are opening listening sockets on high ports, and reading some standard system properties.
Not many succeeded in solving this one. The ones who did, and their solutions can be admired below as time-travelling comments that were posted before this blog post appeared.
The fact that this hack is possible makes me wonder. Is all privileged code in Java itself really prepared to crash at any time? Including all native code? If an applet makes the loading of a class fail in this way; does that cause
NoClassDefFoundErrors in other applets? How else could this be abused?...
Please, don't try this at home. Car insurance usually doesn't cover the failing of the crashing of the crash. Even if you first tried crashing without the car; running with your head straight into the tree. Blowing up the car right before it hits the tree is not appreciated either.