Runtime — SIMD-0706

Which Solana Programs Still Depend on the Legacy Allocation Syscall?

10 min read
SolanaRuntimeSBPFSyscalls

sol_alloc_free_ is how the first Solana programs got heap memory: they asked the runtime for it. New deployments that use it have been rejected on mainnet since August 2023, yet it still runs every day, mostly inside one program, Memo v1. And a newer program format can deploy it again.

SIMD-0706, proposed on 26 October, closes that gap and puts a price on every remaining call; Agave #16661 implements it. Both were open on 4 November. We scanned program binaries for the syscall, counted its calls by running Memo v1’s mainnet binary, and checked the deployment rule before and after.


How a banned syscall became deployable again

The ban was written in May 2022 and its feature, disable_deploy_of_alloc_free_syscall, activated on mainnet on 2 August 2023. Agave builds the deployment environment without the syscall, while the execution environment keeps it, so programs deployed earlier keep running.

That check works by name. Programs built for SBPFv0 to v2 link each syscall by name, and deployment rejects a name the environment lacks. SBPFv3, through static syscalls, calls syscalls by number, and Agave’s on-chain verifier does not look the numbers up. We built one small program that calls sol_alloc_free_ for both versions and ran Agave’s deployment check on it with solana-sbpf 0.27.0:

textA program that calls sol_alloc_free_
            deploy today                deploy with SIMD-0706     loads to run
SBPFv0      rejected: UnresolvedSymbol  rejected                  yes
SBPFv3      accepted                    rejected: InvalidSyscall  yes

The fix needed the VM first. solana-sbpf 0.27.0, released on 3 November, adds an option that makes the verifier reject static calls to unregistered syscalls (#292). Agave #16661 turns it on for deployments and upgrades behind a feature that still has a placeholder key. It leaves it off for ExtendProgram and core-program migrations, so nothing already deployed is newly rejected. The SIMD’s title covers the wider effect: any SBPFv3 call to a syscall the environment does not register is rejected, not only this one.


Finding the syscall in a binary

The two formats hide syscalls in different places, so the scan has two halves. We wrote it with nothing but Python’s standard library:

textSyscalls an SBF program references
1. solana program dump <PROGRAM_ID> program.so
2. read e_flags in the ELF header: 0-2 is SBPFv0-v2, 3 is SBPFv3
3. SBPFv0-v2: in every SHT_REL section, take relocations of type 10
   (R_SBF_64_32) whose dynamic symbol has value 0; the symbol
   name is the syscall
4. SBPFv3: in .text, take call instructions (opcode 0x85) with
   source register 0; the immediate is murmur3_32(name)
5. sol_alloc_free_ is 0x83F00E8F

A relocation against a defined symbol is a call between the program’s own functions, not a syscall, which is why the value check matters. We checked the scanner against our own builds before pointing it at mainnet.


Who still depends on it

The SIMD counts 209 older programs that may call the syscall, names Memo v1 as the only heavy user, and lists three more with any use in the past month. We fetched those four binaries from mainnet, plus fourteen of the most-used programs:

textsol_alloc_free_ in mainnet binaries (all SBPFv0)
program            loader             deployed     call sites
Memo v1            BPF loader v1      -            4
95o7H8q...         upgradeable        Jan 2023     11
B1hM7ws...         upgradeable        Jun 2022     9
CpbvNz3...         upgradeable        May 2022     32

Memo v2, SPL Token, Token-2022, Associated Token,
Token Metadata, Jupiter v6, Raydium AMM v4 and CLMM,
Orca Whirlpools, Meteora DLMM, Pump.fun, Squads v4,
Stake, Address Lookup Table                     none

All four callers reference it; none of the fourteen do. Every binary in the sample is SBPFv0, the busiest programs included, so the SBPFv3 gap is about programs that do not exist yet. The three upgradeable callers can still be upgraded, but only with a build that drops the syscall.

The SIMD dates the ban to 2022, when it was written. On mainnet it took effect in August 2023, and 95o7H8q… was deployed with the syscall in January 2023, more than six months before that.


What Memo v1 will pay

SIMD-0706 charges each call the syscall base cost, 100 compute units. We ran Memo v1’s mainnet binary in solana-sbpf with its input laid out the way Agave’s deprecated loader lays it out, and Agave’s allocator for that loader: a bump allocator over a 32 KiB heap whose frees do nothing. Memo v1 never touches its accounts, but the SDK entrypoint it was built with allocates while unpacking them.

textMemo v1, a 16-byte memo
accounts  allocs  frees  calls  CU today  CU with SIMD-0706
0         0       0      0      259       259
1         3       3      6      661       1,261
2         5       5      10     724       1,724
3         7       7      14     1,097     2,497
4         9       9      18     1,160     2,960

That is 4n + 2 calls for n accounts, the SIMD’s figure, half of them frees that cost nothing today and would cost 100 each. Today’s compute units are the harness’s instruction counts, which matched mainnet simulations for zero, one and two accounts exactly. With one account a memo nearly doubles in cost; without accounts, which the SIMD finds in 75% of Memo v1 instructions, nothing changes.

Memo v1, one account, today661 CU
Same, with SIMD-07061,261 CU
Memo v2 references sol_alloc_free_no

Memo v1 cannot be upgraded, so its callers can only move to a different program. Memo v2 does not use the syscall, but it is not a drop-in replacement: it requires every account passed to it to have signed, which Memo v1 never checked.


Across runtime versions

SBPFv0–v2 caller: deploy or upgraderejected
SBPFv0–v2 caller: execution todayruns
SBPFv0–v2 caller: execution with SIMD-0706+100 CU / call
SBPFv3 caller: deploy todayaccepted
SBPFv3 caller: deploy with SIMD-0706rejected
Any SBPFv3 call to an unregistered syscallrejected

Only the last three rows depend on the new verifier option, and they apply only once the feature activates. A deployment tool that already checks SBPFv3 binaries locally, as the Solana CLI does against the cluster’s current features, catches both cases today.


What this does not show

We scanned 18 programs, not the corpus; the count of 209 and the usage figures are the SIMD’s. The call counts come from solana-sbpf 0.26.0 with Agave’s serialization and allocator rebuilt in our harness, checked against mainnet simulation; the deployment results from solana-sbpf 0.27.0 with Agave’s deployment environment rebuilt the same way, not from a validator. Our local Agave 4.2.1 test validator, which activates every feature, could not run Memo v1 with accounts at all: it failed with an access violation in its input region. Its bundled Memo v1 is also a different build from mainnet’s, with the same syscalls.


sol_alloc_free_: Questions People Actually Ask

What is sol_alloc_free_ on Solana?

The original heap syscall: a program asked the runtime to allocate memory from its 32 KiB heap instead of running its own allocator. Frees are accepted but do nothing. Modern programs bring their own bump allocator; what still calls it is old SDK entrypoints, on every allocation and free while unpacking the accounts they are given.

Can you still deploy a Solana program that uses sol_alloc_free_?

Not an SBPFv0, v1 or v2 program: since 2 August 2023 mainnet’s deployment check has rejected the name. An SBPFv3 program, which calls syscalls by number, still deploys today, because the on-chain verifier does not look the number up. SIMD-0706, with Agave #16661, would reject it.

How do I check whether my Solana program calls sol_alloc_free_?

Dump the program with solana program dump and look at its syscalls. For SBPFv0 to v2, list the R_SBF_64_32 relocations against undefined dynamic symbols; the syscall names appear as symbol names. For SBPFv3, look for call instructions with source register 0 and the immediate 0x83F00E8F, the murmur3 hash of the name.

How much more will Memo v1 cost under SIMD-0706?

Memo v1 calls the syscall 4n + 2 times for n accounts and not at all with none. At 100 compute units per call, an instruction with one account goes from 661 to 1,261 units and one with two accounts from 724 to 1,724. Instructions without accounts stay at 259.

What does SIMD-0706 change for SBPFv3 programs?

Deployment and upgrades would reject any SBPFv3 program that calls sol_alloc_free_ or any syscall the deployment environment does not register. Today such programs deploy and fail only when they reach the call. Programs already deployed are not re-checked.


The one-line version

sol_alloc_free_ survives in old SBPFv0 binaries led by Memo v1, which SIMD-0706 would charge 100 compute units per call, while SBPFv3 can still deploy it today because the on-chain verifier does not check syscall numbers, a gap solana-sbpf 0.27.0 and Agave #16661 close.

Sources: SIMD-0706 and Agave #16661 as of 4 November; solana-sbpf 0.27.0 and #292; Agave master at 4fd1753c; the 2022 ban and its mainnet feature account. Binaries are mainnet’s; the scanner and harnesses are our own.

xroot.devOn-chain research, published in full
𝕏 @xrootdev
← Back to all notes