Consider the following simple contract:

pragma solidity ^0.4.16;

contract TestContract {

    function add(uint256 amount) returns (uint256) {
       require(amount > 0);

       return 100 + amount;
    }
}

I would expect that the result of this function is always greater than 100. Except for an uint overflow scenario, but let's not discuss that.

If i call the function from geth like this the result is like expected 105.

> testInstance.add.call(5)

If i call the function with an negative number, i would expect that an exception is thrown or that the input is changed to zero and the result is 100, but instead in returns 95.

> testInstance.add.call(-5)

So how is that possible? Has anyone an idea? Is it just bad practice to pass negative numbers to the function?

  • 2
    If you change uint256 to int256 it will work as expected. – Ismael Dec 19 '17 at 14:30
up vote 2 down vote accepted

I'm not 100% sure, but I believe this is exactly the integer overflow you mentioned.

I agree that on the web3 side, passing a negative number should probably be treated as an error. But on the Solidity side, I assume what your function receives is a 32-byte representation of the two's complement value for -5 (a really big number). When added to 100, taking into account integer overflow, the result is 95.

  • 1
    I guess you're right, it's the integer overflow. If i just return the input parameter, i can see that it is a very big number. Thank you for the fast answer! – Oliver Schwab Dec 19 '17 at 14:04

I just wanted to add the reason why there is no exception raised. In Solidity Issues on GitHub the similar question was raised. And here is the answer:

Forget about two's complement, this is just how it is represented internally, but the math should work out even without having to think about two's complement. Here is how it works:

Operations on variables of uint are performed in the ring mod 2^256. Furthermore, if x and y are uint variables, then certainly something like x-y should be possible (and is just computed mod 2^256). Since -a is just a short hand for 0-a, I don't see why it should be disallowed. Since 0 is equivalent to 2^256, is is just natural that -1 is the same as 2^256-1, which is 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff.

By the way. I tried your code in remix, and remix is constantly throwing error about passing negative numbers to uint variables even before it goes to require function.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.