April 5, 2007, 12:44 p.m.

Heisenbugs and Assertions

According to wikipedia:

A heisenbug is a computer bug that disappears or alters its characteristics when it is researched.

In my experience writing such bugs, they're often due to race conditions or buffer initialization problems that go away when the timing is just right, or the right conditions occur.

Last night, however, I discovered that I'd written a very explicit heisenbug: My bug went as far as to actively detect when debugging was enabled, and behave properly, but when nobody was looking, it would cause catastrophic failures in my library (that is, all users of the library would hang indefinitely unless they were using my asynchronous methods with a timeout).

For the punchline, see this changeset.

Basically, I always run java with assertions enabled (that is, actively looking for bugs). Last night, I happened to run a test without assertions enabled for some reason, and nothing worked at all. In the above example, my assertion had a side-effect (this is nio code where data is a ByteBuffer where get() retrieves the value at the current position in the buffer and moves the position forward). By calling get() within the assert line, I save a line of code and all kinds of cool stuff, but if you disable assertions, the line never gets called at all.

assert was probably my favorite addition to java 1.4. I encourage everyone to run their jvms with -ea and add assert statements all over their code. It's easier to write a line that looks like this:

  assert val <= MAX_VAL : val + " is too big";

Than it is to write something like this:

  if(val > MAX_VAL) {
    throw new SomeKindOfException(val + " is too big");
  }

Being easier is important. It means you're likely to do it more often. If you're really lazy, you could also leave off the message. An assertion without a message is way better than no assertion when your app starts acting up.

Also, being something easy to enable and disable at runtime means you don't have to think about the cost of the assertions too much. If you suspect assertions on a particular class are slowing down your app, you can just disable assertions for that class.

So, assert everything, but make sure your assertions never have side effects.

blog comments powered by Disqus