argotorg / argotorg/solidity

Memory allocation on non-memory returndata

Open
#16,440 5 comments 0 reactions 0 assignees View on GitHub
medium effort medium impact viair
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.