Memory allocation on non-memory returndata
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 29
Description
Let's consider the following Solidity code:
```js
function batch(address[] calldata to) external {
for (uint256 i = 0; i < to.length; i++) {
require(ERC20(address(0xdeadbeef)).transfer(to[i], 1 ether));
}
}
```
This code should be deployable for production, but it isn't! This is because the gas complexity of this code is not linear with `to.length`. It's quadratic.
The complexity breaks because Solidity allocates memory (pushing the free memory pointer!) when *decoding* the returndata of the call, even for data that is not to be stored in memory. So, ERC20 returning `bool` will now push the free memory pointer by 32 bytes on each iteration. The total cost of memory allocation is quadratic, which increases the total gas complexity from linear to quadratic.
In order to fix this, one is forced to use Yul assembly rather than standard Solidity. This should never happen for such a common use case like batching simple operations.
Solidity should allocate memory (i.e. bump the free memory pointer) only if:
- the return variable is a memory variable, not a stack-based one; and
- the respective return value is used (as an argument or assigned to a variable)
## Environment
- Compiler version: 0.8.31
- Compilation pipeline: IR
- Target EVM version: prague
Contributor guide
Research direction
Use the provided Solidity batch example with compiler 0.8.31, the IR pipeline, and the Prague target as the reproduction case. Trace returndata decoding and free-memory-pointer changes across loop iterations; done means unused stack-based return values no longer cause repeated memory allocation and the gas growth is linear, with regression coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100