0

I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this Orz.

I'm doing some security-related attempts on Ethereum EVM (very immature, just an interesting attempt), and now I need to distinguish between int and uint types in EVM.

pragma solidity >=0.4.22 <0.6.0;
contract calc256{
    uint uresult;
    int result;

    function uadd(uint _a,uint _b) public returns(uint){
        uresult = _a + _b;
        return uresult;
    }

    function iadd(int _a, int _b) public returns(int){
        result = _a + _b;
        return result;
    }
}

For example, the func uadd() and iadd() produce exactly the same opcode. So I can't distinguish between the two data types inside evm

  • For uadd () function, input _a = 0xfff .... fe, _b = 3, the actual input in evm is (0xfff .... fe, 3) (actually caused an overflow)

  • For the iadd () function, input _a = -2, _b = 3, and the actual input in evm is also (0xfff .... fe, 3) (correct).

That is, the unsigned positive integers 0xfff...fe and the negative number -2 are represented both as 0xfff...fe when calculating in evm. I know that Ethereum relies on two's complement to represent signed numbers, but is there any way to make evm distinguish between 0xfff...fe and -2?

Thanks in advance.

  • Signed 0xfff .... fe is -2, not -1 (your comparison between the two functions is therefore wrong)! – goodvibration Dec 30 '19 at 10:38
  • Sorry, this is a typo, I will correct it immediately, but the problem still exists – CapybaraJ Dec 30 '19 at 12:24
  • There's no flags-register which you can check during runtime in order to determine whether or not an overflow has occurred (in contrast with most common HW architectures). The result is the same (1), as you've already noted, and so are the opcodes (also as you've noted, though in this case I just trust your word for it, have you verified this in the disassembly?). So if you you're looking for a way to determine potential overflows by looking into the byte-code, then I guess that the answer is - N/A (again, given that you verify your statement in the disassembly of a short code snippet). – goodvibration Dec 30 '19 at 12:40
  • I did locally verify and compare the opcodes of the two funcions in evm, which are exactly the same, which really makes me desperate. I was wondering if I can modify the compiler so that when it encounters the int256 type, add A flag instruction (I know this is stupid, but I have to find some way to make my whole idea work) – CapybaraJ Dec 30 '19 at 14:35
  • Of course you can, the compiler source code is available at github.com/ethereum/solidity. I hope you know your way around C++. – goodvibration Dec 30 '19 at 14:42
2

Tested the following code:

pragma solidity ^0.5.0;

contract Test {
    function iadd(int a, int b) public pure returns (int) {return a + b;}
    function uadd(uint a, uint b) public pure returns (uint) {return a + b;}
}

Using solc 0.5.13:

solc --bin --abi --asm --output-dir=binaries Test.sol                                                                             

The disassembly (opcodes) of functions iadd and uadd is indeed identical (see below).

If you add --optimize --optimize-runs=200 to the command-line above, then the compiler even omits the second function (uadd) from the output, leaving only the first function (iadd).

Here is the disassembly of function iadd when optimization is not enabled:

      dup2
      add
      swap1
      dup1
      dup1
      calldataload
      swap1
      0x20
      add
      swap1
      swap3
      swap2
      swap1
      dup1
      calldataload
      swap1
      0x20
      add
      swap1
      swap3
      swap2
      swap1
      pop
      pop
      pop
      tag_7
      jump  // in
    tag_5:
      mload(0x40)
      dup1
      dup3
      dup2
      mstore
      0x20
      add
      swap2
      pop
      pop
      mload(0x40)
      dup1
      swap2
      sub
      swap1
      return

The only difference from the disassembly of function uadd is those two tag names (tag_7 and tag_5 in this case).

in contrast with common HW architectures such as x86 and x64, there is no such thing as a flags-register which you can check during runtime in order to determine whether or not an overflow has occurred.

I guess you could change the compiler source code to somehow differentiate between signed-integer operations and unsigned-integer operations, though I believe that there's a good reason for why they've chosen to avoid this.

Of course, even if you do, it's not gonna help you with already-compiled-and-deployed contracts.

  • I think the Ethereum developers use the two's complement method so they do not need to distinguish int & uint during compilation. Thank you for your answer sincerely! – CapybaraJ Dec 31 '19 at 3:12
  • @CapybaraJ: You're welcome :) – goodvibration Dec 31 '19 at 4:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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