What's Wrong With This Code (#18)

Here is another golden oldie:

Numeric overflows are a type of software bug that occur when a calculation produces a result that doesn't fit in the intended storage location. One of the most famous cases of an overflow bug is the overflow bug that destroyed an Ariane 5 rocket in 1996*.

Fortunately, .NET has a dedicated exception to highlight overflow problems. Just run the following VB code and watch the OverflowException appear.

Dim i As Integer
i += Integer.MaxValue
i +=
Integer.MaxValue

So, given this class:

public class LineItem
{
    
private int _quantity;
    
public int Quantity
    {
        
get { return _quantity; }
    }

    
public int AddQuantity(int additionalQuantity)
    {
        
// some logic ...
        return _quantity += additionalQuantity;
    }

    
// other stuff...
}

Why does the following unit test fail?

[TestFixture]
public class LineItemTest
{
    [
Test]
    [
ExpectedException(typeof(OverflowException))]
    
public void TestForOverflow()
    {
        
LineItem lineItem = new LineItem();
        lineItem.AddQuantity(
Int32.MaxValue);
        lineItem.AddQuantity(
Int32.MaxValue);
    }
}

What options are available to fix the problem?

* The article Design By Contract: The Lessons Of Ariane says the real error was a "reuse specification error". Quote: "To attempt to reuse software without Eiffel-like assertions is to invite failures of potentially disastrous consequences".

posted on Monday, October 08, 2007 11:01 PM by scott

Comments

Monday, October 08, 2007 9:43 PM by Jonas

# re: What's Wrong With This Code (#18)

The unit test fails because when Int32.MaxValue is passed to AddQuantity for the second time, _quantity overflows, as it's already at Int32.MaxValue.
Monday, October 08, 2007 10:37 PM by Jonathan Malek

# re: What's Wrong With This Code (#18)

I think it should be:

return checked(_quantity += additionalQuantity);

So that runtime overflow checking is applied. You can also use /checked+ as a compiler switch instead of the statement or block.
Monday, October 08, 2007 10:49 PM by Kalpesh

# re: What's Wrong With This Code (#18)

The unit test would fail because the value is returned before += could execute? To make it throw the exception, it should read

_quantity += additionalQuantity;
return _quantity;

Just a wild guess. I didn't try running it.
Monday, October 08, 2007 11:57 PM by Jason Stangroome

# re: What's Wrong With This Code (#18)

VB projects have an advanced compile optimization to remove integer overflow checks. This is off by default so VB checks for and throws OverflowExceptions.

C# projects have advanced build settings to check for arithmetic overflow/underflow. This is off by default so C# does not check for overflow and does not throw exceptions.

To pass the unit test without enabling overflow checks for the whole project and assuming only non-negative numbers are valid for the additionalQuantity field (yet another unit test) I would add the following guard clause:

if (_quantity > Int32.MaxValue - additionalQuantity) throw new OverflowException();
Tuesday, October 09, 2007 12:05 AM by Ronin

# re: What's Wrong With This Code (#18)

Well i suppose you should you checked construct in AddQuantity, else compiler won't throw an exception, will just round up.
Tuesday, October 09, 2007 12:08 AM by Ronin

# re: What's Wrong With This Code (#18)

You need to use checked construct in AddQuantity method in order to ensure that the compiler will throw an exception.
The default behavior is to round-up.
Tuesday, October 09, 2007 3:49 AM by Dave

# re: What's Wrong With This Code (#18)

I believe this is down to the fact that by default VB checks for overflows at runtime which C# by default does not. Thus, the test will fail .

The simple of way of getting the exception to throw (and the test to pass) is to use the checked keyword so that the addition of the two integers is checked at runtime or you also set the /checked switch on the compiler to make sure that all integer arithmetic is overflow checked.
Tuesday, October 09, 2007 3:35 PM by Eric D. Burdo

# re: What's Wrong With This Code (#18)

Another potential problem. You have an Int32, and an Int. This doesn't guarantee that the Int will be 32 bits (depends on the platform and such).
Tuesday, October 09, 2007 5:48 PM by scott

# re: What's Wrong With This Code (#18)

Good catch!
Wednesday, October 10, 2007 6:26 PM by BusinessRx Reading List

# Overflow Exceptions

WWWTC #18 highlights the fact that integer overflow detection is ON by default for Visual Basic projects.
Thursday, October 11, 2007 4:41 PM by K. Scott Allen

# Overflow Exceptions

WWWTC #18 highlights the fact that integer overflow detection is ON by default for Visual Basic projects....
Thursday, October 11, 2007 7:25 PM by Christopher Steen

# Link Listing - October 11, 2007

Link Listing - October 11, 2007
Thursday, October 11, 2007 7:28 PM by Christopher Steen

# Link Listing - October 11, 2007

Regional SharePoint Users Conference October 27-28 [Via: Gary Blatt ] SOAP/TCP Transport for WCF [Via:...
Thursday, October 11, 2007 7:55 PM by Scott McMaster

# re: What's Wrong With This Code (#18)

Re: int versus Int32 a couple of comments above, "int" in C# IS guaranteed to be 32 bits == "Int32" per spec. The "platform" in this case IS .NET. The designers didn't want to propagate the old C/C++ data type sizing mess.
Wednesday, November 14, 2007 6:02 PM by Community Blogs

# Overflow Exceptions

WWWTC #18 highlights the fact that integer overflow detection is ON by default for Visual Basic projects