Beware Math.abs()

If the title didn’t tip you off, this is going to be a technical post. So you might want to skip it if you’re only here to read about how my thumb is doing (very well, incidentally).

Anyway, onto the subject at hand.

I recently had cause to look at the list of bugs that FindBugs looks for when analyzing your Java code. If you haven’t heard of it, FindBugs is a free software static analysis tool. In a nutshell it looks through your source code trying to find coding patterns that it knows can be the causes of bugs. It’s not a replacement for testing by any means, but it is a useful addition to your quality tools.

What’s especially useful is the fact that FindBugs tends to uncover bugs that you might not even know are possible—and thus probably haven’t tested for. Have a look at the list of issues it looks for to see what it can do. There are a few hundred issues listed there, so this could take you some time. I’ll wait.

Assuming you didn’t bother to read about all of those bug types, I’m going to call out one that I found particularly interesting. It’s what FindBugs calls, “Bad attempt to compute absolute value of signed 32-bit hashcode”. As the tool’s documentation describes it:

This code generates a hashcode and then computes the absolute value of that hashcode. If the hashcode is Integer.MIN_VALUE, then the result will be negative as well (since Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE).

The interesting point here is that last parenthesized statement, that the expression Math.abs(Integer.MIN_VALUE) is equivalent to Integer.MIN_VALUE. It’s a surprising result, and one that can cause real problems if the programmer responsible for the code was expecting that call to always yield a positive value.

Recall that the range of integers that can be represented in 32 bits is -2,147,483,648 – 2,147,483,647. That is, the true absolute value of Integer.MIN_VALUE can not be represented as an int. The possibilities—from the perspective of the person who designed the Math library—are to have Math.abs() throw an exception when passed that argument, or to just return the number as-is. Neither of these are particularly useful to the developer,  since the error condition only shows up only one time in over four billion.

The FindBugs blog has more on this potential bug, including some examples of when it might occur. Author Bill Pugh explains why the case of calling Math.abs() on the result of a hashcode computation is a particular source of trouble.

Now that you’re aware of the potential for this bug to crop up in your code, what should you do about it? Well it would certainly help to run FindBugs against your codebase periodically to look for this bug and others. It really is amazing how many issues can show up even in well-tested code. The potential for human error in complex systems is almost limitless.

If you’re not happy with relying on static analysis and want to test for the bug in a unit test or regression test, you might find use for a string whose hashcode happens to be Integer.MIN_VALUE. Examples of these, again from the bug’s documentation, are “polygenelubricants” “GydZG_” and “”DESIGNING WORKHOUSES”. Take your pick.