Repository navigation
bugc: keep a slice of calldata in calldata - #367
Merged
Merged
Conversation
gnidan
added a commit
that referenced
this pull request
Oct 7, 2026
Contributor
|
A slice of msg.data, or of another slice of calldata, now refers to the calldata instead of copying it to memory. Its value is one word: the offset in the high 128 bits, the length in the low 128 bits. A local's pointer reads that word and then a calldata region whose offset and length are computed from it. A let typed `bytes`, an assignment to memory or storage, a cast to `bytes` or `string`, a call argument, a return value and the argument of keccak256 copy the bytes to memory.
gnidan
added a commit
that referenced
this pull request
Oct 7, 2026
gnidan
force-pushed
the
bugc-calldata-slices
branch
from
October 7, 2026 03:08
f9146fa to
a8b08cc
Compare
`let text: bytes calldata = msg.data[a:b]` is a calldata reference, as an untyped slice of msg.data is; `let text: bytes = ...` copies to memory. `bytes calldata` can only be the type of a let or of a cast.
gnidan
force-pushed
the
bugc-calldata-slices
branch
from
October 7, 2026 03:16
a8b08cc to
79c5fb3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A slice of
msg.datanow refers to the calldata instead of copying it to memory, so a BUG program can hold calldata bytes in a local and its debug info can say exactly which calldata bytes the local holds. For example, with asetMotd(string)call:textis nowbytes calldata. Its value is one word: the offset of its first byte in the high 128 bits, and its length in the low 128 bits. Somsg.dataitself is the calldata size, and the IR needs no new instruction: a slice is ashland anor,.lengthis anand,text[i]is a one-byte calldataread(CALLDATALOAD), and a slice oftextis calldata too. A cast tobytesNloads the first 32 bytes withCALLDATALOADand zeros the bytes past the length, as it does for memory.The local's pointer names its word, and then the bytes:
{ "name": "text-data", "location": "calldata", "offset": { "$quotient": [{ "$read": "text" }, "0x100000000000000000000000000000000"] }, "length": { "$remainder": [{ "$read": "text" }, "0x100000000000000000000000000000000"] } }This reads exactly the right bytes when the bounds are computed at run time, as above. The pointer uses
$-prefixed expressions, since #323 (~) is not merged.The type says where the bytes are, as in Solidity. The spelling is
bytes calldata: Solidity's order, and the way the compiler already prints the type. BUG has no other location or qualifier words, so there was no BUG form to follow.calldatais not reserved; it is a keyword only right afterbytesin a type.msg.dataand its slices arebytes calldata, so an untypedlet text = msg.data[a:b]is a calldata reference as well.bytes, wherever it is written, means memory, solet text: bytes = msg.data[a:b]is a copy.bytes calldatacan only be the whole type of aletor of a cast: a parameter, return type, struct field, storage variable or nested type ofbytes calldatais a type error (TYPE016).These copy bytes in calldata to memory (
CALLDATACOPY, through thecopyinstruction from #359): alettypedbytes, an assignment to abyteslocal, a cast tobytesorstring, a function argument or return value, and the argument ofkeccak256. Assigning to abytesorstringstorage variable copies, then stores the bytes through #355's storage encoding, somotd = text as string;stores the string as Solidity does. These are type errors: writing to bytes in calldata (text[0] = 1), assigning memory bytes to abytes calldatalocal, and casting memory bytes tobytes calldata.Tests that wrote into a slice of
msg.datanow type the localbytes, so it is a copy in memory.examples/advanced/token-registry.bug(@wip) does the same for its selector, which it compares with memory bytes.The new test reads, stores, copies, slices, casts and bounds-checks calldata slices of 0, 5, 31, 32 and 50 bytes at levels 0 to 3. It reads and stores each one as
let text,let text: bytes calldataandlet text: bytes. The locals harness can now run with calldata and read calldata regions, and new soundness cases run thesetMotdprogram above with the same three spellings. At every level,text's pointer reads its bytes at every step where it is listed: the calldata for the first two spellings, the memory copy for the third. The emitted program validates against the schema. Bytecode and debug info for the programs inexamples/that do not slice calldata are unchanged at all levels; the four that do (calldata,strings,token-registry,voting-system) change.The BUG case study in the docs has a new section on bytes in calldata.