1

While reading https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html#abi I was just thinking what happens when calldata contains more parameters/data than the function expects (I know first parameter is 4 bytes Keccak256 of function signature, so this cannot happen by accident). It's just that you can use arbitrary msg.data. I believe those exta bytes should be just silently ignored (never referenced) or am I mistaken? This means the exact same function invocation can be encoded in many different ways.

Additionally: what happens if dynamic array "offset" points outside of the given parameters (or size is bigger than actual number of provided values). Can you imagine that everything undefined is sort of 0 or will such tricks throw an exception?

0

Yes, the extra calldata bytes will be ignored, and yes, calldata read past the end of the length is 0s.

1

Adding to smarx's answer (extra calldata is ignored):

Additionally: what happens if dynamic array "offset" points outside of the given parameters (or size is bigger than actual number of provided values). Can you imagine that everything undefined is sort of 0 or will such tricks throw an exception?

For dynamic size objects like bytes/strings/arrays, if size is bigger than the number of provided values in calldata, you'll get a REVERT.

You can test this yourself in Remix with the following code:

pragma solidity ^0.5.0;

contract X {
    event E(bytes data);

    function b(bytes memory _b) public {
        emit E(msg.data);
    }
}

contract Test {
    event E(bytes data);

    X x = new X();

    function b(bytes memory _b) public payable {

        emit E(msg.data);

        // shorten calldata by 30 bytes
        bytes memory callData = new bytes(msg.data.length-30);

        for(uint i=0; i<callData.length && i<msg.data.length; i++) {
            callData[i] = msg.data[i];
        }

        // this will work fine as long as _b.length <= 2
        (bool res, bytes memory ret) = address(x).call(callData);

        assert(res);
    }

}
0

I dug a bit into the EVM bytecode and found out that it explicitly checks CALLDATASIZE. Also a non-payable function gets the if (msg.value != 0) revert compiled in automatically. So to answer my own question if you just read any (uninitialized) memory you will get back 0, but for the generated function Solidity compiler seems to automatically add checks that do a REVERT in the LT (lower-than) case (if there is too much data nothing bad will happen). So Solidity itself sort of ensures that certain conditions about the parameters hold, there is no other magic involved.

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.