3

I ran the code below and had a question.

function mloadTest1() public pure returns(bytes memory) {
    bytes memory a;

    assembly {
        a :=mload(0x40)
    }

    return a;
}

mload(x) is a Yul code that reads 32 bytes from offset x in memory. And Solidity defaults to free memory points from 0x00 to 0x60, with 0x80 stored at 0x40.

So I think the value of the last return a in the above code should be 0x80, but the result was 0x20, which I don't understand.

Can anyone explain these results?

2 Answers 2

4
+50

Unlike value types like bytesN or uintN reference types (denoted by their memory, calldata or storage annotation) are merely pointers to their underlying data.

When you use inline-assembly to set a what you are setting is actually the pointer of that variable not the value of the byte-string itself. As you've stated correctly the free memory pointer at 0x40 initially holds 0x80, meaning when you do a := mload(0x40) you're essentially saying "the bytes variable a now points to the memory offset 0x80.

Considering that the memory is empty and the offset that a bytes object points to holds its length, Solidity interprets this as a bytes of length 0 because the word (32-byte segment) at 0x80 is 0.

When you then return the bytes Solidity proceeds to ABI encode it. Return values are encoded as a tuple of values, in this case a tuple with a single bytes: (bytes,). For variable length values such as bytes ABI encoding first encodes the offset in the return data, before encoding the length and actual data at that offset.

So the data you're getting should be interpreted as follows:

0x

offset of the first `bytes` value (32 bytes in the return data):
0000000000000000000000000000000000000000000000000000000000000020
at the encoded offset (32) the actual length of the `bytes` (0):
0000000000000000000000000000000000000000000000000000000000000000
5

Your reasoning is correct, but only for values of type bytes32 or uint256. The next code will return 0x80

function mloadTest1() public pure returns(bytes32) {
    bytes32 a;
    assembly {
        a := mload(0x40)
    }
    return a;
}

Variables of type bytes (and string) are special arrays. The bytes type is similar to bytes1[], but it is densely packed in calldata and memory. By default, such an array is initiated with empty values of 32 bytes1. Despite the fact that the value 0x80 lies at this address, the type conversion returned not an array of bytes but its length == 32 bytes1. (0х20)

1
  • Um... I still don't understand, why is the length of the data stored in the bytes variable(a) of dynamic type?
    – imelon2
    Jan 6 at 10:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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