Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting integer overflow

Tags:

int

d

How to detect integer overflow in D? (check carry flag?)

Original example:

ubyte a = 100;
ubyte b = 200;
ubyte c = a + b;
// c can't represent 300; how to detect the overflow now?

Revised example:

uint a = 2_000_000_000;
uint b = 3_000_000_000;
uint c = a + b;
// c can't represent 5_000_000_000; how to detect the overflow now?

Also with multiplication and pre/post-increment.

like image 825
Core Xii Avatar asked Nov 25 '12 00:11

Core Xii


People also ask

How can you tell if an integer is overflow 32-bit?

You need to check reversed before the multiplication. If it is bigger than INT_MAX/10, then it will overflow. And maybe you need other checks too. The working of your code assumes the value being reversed AND the reversed value can both be represented in a 32-bit integral type.

What are the means used to detect and prevent integer overflow?

Following are the three main techniques for detecting unintended integer overflow: Precondition testing. Check the inputs to each arithmetic operator to ensure that overflow cannot occur. Throw an ArithmeticException when the operation would overflow if it were performed; otherwise, perform the operation.

How do you solve integer overflow problems?

In languages where integer overflow can occur, you can reduce its likelihood by using larger integer types, like Java's long or C's long long int. If you need to store something even bigger, there are libraries built to handle arbitrarily large numbers.


2 Answers

For starters, the code that you gave won't even compile, because all integer math with sizes smaller than int is done with int. So the result of a + b is int, and int will not implicitly convert to ubyte, because that's a narrowing conversion. If you want to assign it to c, then you'll need to cast it.

ubyte c = cast(ubyte)(a + b);

Now, that's obviously an unchecked conversion, and it will happily stuff 44 into c (since that's the result of the cast given the values of 100 and 200). If you want a checked conversion, then use std.conv.to:

ubyte c = to!ubyte(a + b);

That will throw a ConvOverflowException (which is a subclass of ConvException), because the result won't fit in the requested type.

If you want to do the cast yourself and then check whether there was overflow, then you're in essentially the same boat as C/C++, and there are no carry flags or anything of the sort. Maybe that sort of thing exists if you check with assembly code. I don't know. But the language certainly doesn't provide anything like that. std.conv.to figures it out by checking the result and seeing if it is too large or too small (depending on the sign and types of the argument).

like image 197
Jonathan M Davis Avatar answered Sep 30 '22 03:09

Jonathan M Davis


Update in 2021: this technique only works if you use dmd without optimizations (and even then probably better to do other approaches). To work in more cases, you can do all the operations in inline assembly (which btw is likely to break optimizers), or use the core.checkedint operations which have a ref bool overflowed argument you can check at the end of the operation (which is also inline-friendly btw for the optimizer again).

Original post follows:

You can check it pretty easily with some inline assembly:

asm { jo overflowed; } // for checking signed types
// or
asm { jc overflowed; } // use this for checking unsigned types

/* continue going */

return;

overflowed:

/* do whatever to handle it */

Note: you probably can't put this in a function because calling the function can reset the flag. You'll want to put it inline right after the operation you're interested in.

It is possible to make a type that uses operator overloading to throw on overflow: http://arsdnet.net/dcode/ranged.d is one example. Or I think the module is std.bigint in the standard library that avoids overflow by offering an arbitrarily large integer type.

like image 30
Adam D. Ruppe Avatar answered Sep 30 '22 03:09

Adam D. Ruppe