Search code examples
stringsoliditysmartcontractsinteger-overflow

How come there is "Integer Overflow and Underflow" in string variables in smart contracts?


I was analyzing a contract in Oyente. The contract is :

pragma solidity ^0.4.21;

contract Test{
    address admin;

    function Test() public{
        admin = msg.sender;
    }

    string str = "";

    function setStr(string _str) public{
        str = _str;
    }

    function getStr() public view returns (string){
        return str;
    }
}

When I passed this contract to oyente to analyze then the following report came:

INFO:root:contract Test.sol:Test:

INFO:symExec:   ============ Results ===========

INFO:symExec:     EVM Code Coverage:             24.1%

INFO:symExec:     Integer Underflow:             True

INFO:symExec:     Integer Overflow:              True

INFO:symExec:     Parity Multisig Bug 2:         False

INFO:symExec:     Callstack Depth Attack Vulnerability:  False

INFO:symExec:     Transaction-Ordering Dependence (TOD): False

INFO:symExec:     Timestamp Dependency:          False

INFO:symExec:     Re-Entrancy Vulnerability:         False

INFO:symExec:Test.sol:16:9: Warning: Integer Underflow.

        return str

Integer Underflow occurs if:

    return str = 1

INFO:symExec:Test.sol:11:5: Warning: Integer Overflow.

    function setStr(string _str) public{

    ^

Spanning multiple lines.

Integer Overflow occurs if:

    _str = 115792089237316195423570985008687907853269984665640564039457584007913129639932

INFO:symExec:   ====== Analysis Completed ======


It shows Integer overflow and underflow in a string variable. I really don't understand how it could happen or how to solve it. Any help will be appreciated.


Solution

  • That's a false positive result.

    Value of the string type is stored as a byte array, not as an integer. If you convert the specified integers into byte array, and then try to return them as string, the value is not readable.

    Example:

    function getStr2() public view returns (string) {
        bytes memory byteArray = abi.encode(115792089237316195423570985008687907853269984665640564039457584007913129639932);
        return string(byteArray);
    }
    

    Fails in Remix IDE (uses JS VM emulator and ethers.js) with error:

    Failed to decode output: null: invalid codepoint at offset 0; bad codepoint prefix (argument="bytes", value=Uint8Array(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc), code=INVALID_ARGUMENT, version=strings/5.5.0)

    Which signalizes that the "string" contains some UTF-8 bytes but doesn't start with the UTF-8 BOM.


    Same goes for the value 1.

    Solidity strings span across multiple slots (each slot has 32 bytes), where the first slot contains the string length.

    So if they set the str value to 0x01, this suggests the array should have a length of 1. And then - depending on their emulator and the tool implementation, it:

    • Either throws a panic error trying to access unallocated memory. They might interpret it as integer underflow, as it also causes a panic error.
    • Or returns the default slot value 0x0000000000000000000000000000000000000000000000000000000000000000 (32 empty bytes), which is still not the expected value 0x01.