Skip to content

Back to the catalog

Solidity 0.8.37 Release Announcement
soliditylang.orgadvisory

Solidity 0.8.37 Release Announcement

Solidity 0.8.37 release notes disclosing three EF bug-bounty-reported compiler bugs with security implications: deleting an element of a memory bytes array (or converted string) zeroed the full 32-byte word instead of one byte, corrupting adjacent data in the evmasm pipeline (all versions ≤0.8.36); a stack-to-memory spill-slot collision in mutually recursive functions under --via-ir silently overwrote live variables (0.7.2–0.8.36); and require() with a custom error using named arguments encoded parameters in call-site rather than declaration order, producing structurally valid but semantically wrong revert data. The release also adds two non-security miscompilation fixes, an experimental planning-based stack shuffler for the SSA CFG backend, support for the Amsterdam EVM's SLOTNUM opcode (EIP-7843), and removes/deprecates several experimental features.

TL;DR Solidity 0.8.37 fixes three EF bug-bounty compiler bugs: memory byte-array delete corrupting 32 bytes, a mutual-recursion spill-slot overwrite, and misordered ABI encoding of named custom-error args in require().
Document

What it is

Solidity 0.8.37, a bugfix release fixing three security-relevant compiler bugs (all reported via the Ethereum Foundation bug bounty). The catalog summary describes each bug's mechanism and version range; what it omits is the severity triage and the exposure caveats an engineer needs to decide whether patching is urgent.

Severity and exposure (the missing decision inputs)

The release rates two of the three bugs low/medium and one very low. Concretely:

  • Memory bytes element delete clears 32 bytes — affects only the evmasm (legacy) pipeline; the IR pipeline is not affected. b[i] = 0 clears exactly one byte on both pipelines and is a safe workaround. Affects all versions ≤0.8.36.
  • Spill-slot collision across mutual recursion — only triggers under --via-ir, and only in call graphs with mutual recursion. Affects 0.7.2–0.8.36. Closely related to but distinct from the "Unsound Spill In Mutual Recursion" bug fixed in 0.8.36, so upgrading only to 0.8.36 does not cover it.
  • Misordered named parameters in require with custom errors (the very-low one) — only the IR pipeline, only require(cond, MyError({b:2, a:1})) form. No impact on contract state: only the revert data of an already-reverting transaction is wrong. Plain revert MyError({...}) is not affected.

So the practically pressing item is the spill-slot collision for anyone compiling --via-ir with mutually recursive functions, since it silently overwrites live variables — a state-affecting miscompilation. The other two are contained (legacy pipeline only, or revert-data only).

What to do

Upgrade to 0.8.37. If you cannot immediately: on the legacy pipeline, replace delete b[i] with b[i] = 0; treat --via-ir builds with mutual recursion as suspect.

Two additional deprecation warnings worth noting before your next build breaks on them: the pragma experimental ABIEncoderV2 leftover now warns (often pulled in transitively via older forge-std), and the constantinople, petersburg, istanbul, and berlin EVM versions are now deprecated. The --lsp mode and pragma experimental solidity are removed outright.

Caveats

The two other miscompilation fixes (uninitialized packed function pointers on evmasm; constants read in both checked and unchecked contexts) are explicitly not classed as security issues — both require implausible or easily test-detectable usage patterns per the release notes.

Organisations named here

  • Cantina Security
  • EIP-7843
  • Ethereum Foundation bug bounty
  • Ng Sze Hon
  • shaheenfazim

Technologies named here

  • Solidity compiler
  • solc
  • SMTChecker
  • Solidity
  • Ethereum

Techniques named here

  • Memory Byte Array Element Delete Clears 32 Bytes
  • Spill slot collision across mutual recursion
  • Misordered Named Parameters in require with Custom Errors
  • Uninitialized Function Pointers in Packed Storage
  • Constants Read in Both Checked and Unchecked Contexts