On the following source code, memOffset
returns local values such as 96, 128 as the address value. How could I make it return the original address that is located on the memory, is it possible? After function f()
is called, is the memory freed like local variables in C?
Complete source code is here
contract C {
function f(uint a, uint b) constant returns (uint[]) {
assembly {
// Create an dynamic sized array manually.
let memOffset := mload(0x40) // 0x40 is the address where next free memory slot is stored in Solidity.
mstore(memOffset, 0x20) // single dimensional array, data offset is 0x20
mstore(add(memOffset, 32), 2) // Set size to 2
mstore(add(memOffset, 64), a) // array[0] = a
mstore(add(memOffset, 96), b) // array[1] = b
return(memOffset, 128)
}
}
}
Best Answer
Revised as previous answer wasn't completely true as it is possible in memory, but it can only be done in assembly and is quite involved. I've been looking at this quite a lot recently and your issue is primarily down to a memory pointer. There is two reasons why the above won't work in direct memory; the first is the msize opcode should point to the largest accessed memory index, but it doesn't which is being overwritten. The second is that we need to discard the data type size as this will automatically be allocated by the EVM.
As you can see from your example mload is using 0x40 (in memory this will reference bytes 64-96) which is the currently allocated memory size (msize) and is making the msize point to 0x20 (byte 32).
Layout in memory
Source: http://solidity.readthedocs.io/en/develop/miscellaneous.html#layout-in-memory
msize
Source : http://solidity.readthedocs.io/en/develop/assembly.html#opcodes
From the source code:
Source: https://github.com/ethereum/solidity/blob/18a72dbe4668e23aaf38404183b978fbbb1824d1/libevmasm/SemanticInformation.cpp#L63
Example of a test resetting the msize:
Source: https://github.com/ethereum/solidity/blob/6cbb726fb8970c6cb98e9b6a2928ef612ad9d760/test/liblll/EndToEndTest.cpp#L641
Because the code uses a return, it halts execution and returns the value stored in memory which is being referenced.
Source : http://solidity.readthedocs.io/en/develop/assembly.html#opcodes
This will freeze the state of the memory and return the value of the memory which you reference.
In memory solution
Let's look at returning a broken value by altering the code to something like:
We now get an array with invalid values, this is due to additional operations being executed by the contract which is overwriting the memory you allocated. To fix this we need to move where we are writing memory to and let the evm know where the msize should be pointing to.
The above should now return the correct value.
Previous answer: