> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfnote/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfnote/web3-security-research/solidity/memory.md).

# Memory

{% embed url="<https://docs.soliditylang.org/en/latest/internals/layout_in_memory.html>" %}
Layout in Memory - Solidity doc
{% endembed %}

Solidity reserves four 32-byte slots, with specific byte ranges (inclusive of endpoints) being used as follows:

* `0x00` - `0x3f` (64 bytes): scratch space for hashing methods
* `0x40` - `0x5f` (32 bytes): currently allocated memory size (aka. free memory pointer)
* `0x60` - `0x7f` (32 bytes): zero slot

I made a diagram for easier memorization:

<figure><img src="/files/Hm6xzFwunfCGuWR4JCo3" alt=""><figcaption><p>memory layout</p></figcaption></figure>

Scratch space can be used between statements (i.e. within inline assembly). The zero slot is used as initial value for dynamic memory arrays and should never be written to (the free memory pointer points to `0x80` initially).

Solidity always places new objects at the free memory pointer and <mark style="color:red;">**memory is never freed**</mark> (this might change in the future).

{% hint style="danger" %}
Memory is <mark style="color:red;">**NOT**</mark> bitpacked (in contrast with storage). For example, `uint8[4] a` occupies 4 \* 32 = 128 bytes of space in memory but occupies 1 \* 32 = 32 bytes in storage. The same is true for structs.
{% endhint %}

`bytes`/`string` is made of two parts:

1. The first 32 bytes is the length of that `bytes`/`string`
2. The actual value starts from the 33th byte

This fact was used in [Ethernaut MagicNumber](https://ethernaut.openzeppelin.com/level/0xFe18db6501719Ab506683656AAf2F80243F8D0c0):

```solidity
contract MagicNumberHack {
    constructor(MagicNum challenge) {
        // len(bytecode) = 19 = 0x13
        bytes memory bytecode = hex"69602a60005260206000f3600052600a6016f3";
        
        address addr;
        assembly {
            // create(value, offset, size)
            addr := create(0, add(bytecode, 0x20), 0x13)
        }
        
        // Verify if the contract was successfully deployed
        require(addr != address(0));

        // Interact with the challenge contract
        challenge.setSolver(addr);
    }
}
```

Here we used `add(bytecode, 0x20)` to get the actual value of `bytecode` since the first slot is its length and its actual value is in the second slot.
