Skip to content

from_candid: "byte read out of buffer" trap when skipping many record fields (to_candid round-trip) #6331

Description

@ggreif

Summary

A to_candid / from_candid round-trip traps with IDL error: byte read out of buffer when the decode target is a subtype that omits many of the record's fields, i.e. when the decoder has to skip a large number of trailing fields. The threshold is small — in our tests it appears at 213 skipped fields (212 decodes fine, 213 traps).

The blob itself is well-formed: decoding the same value back into its full type (no fields skipped) succeeds. Only the field-skipping path fails.

Steps to reproduce

Generate a record with N Nat fields, encode it, and decode it into the empty record {} (which forces every field to be skipped):

gen() { python3 -c "
n=$1
fields=';'.join('f%d = 0'%i for i in range(n))
types=';'.join('f%d : Nat'%i for i in range(n))
print('import Prim \"mo:⛔\";')
print('type Big = { '+types+' };')
print('let r : Big = { '+fields+' };')
print('let blob = to_candid (r);')
print('switch (from_candid blob : ?({})) { case (?_) Prim.debugPrint(\"ok\"); case null Prim.debugPrint(\"null\") };')
"; }

gen 212 > r212.mo   # decodes: prints "ok"
gen 213 > r213.mo   # traps:   IDL error: byte read out of buffer

Run each with moc -wasi-system-api rNNN.mo -o rNNN.wasm && wasmtime rNNN.wasm.

Observed

case result
212 fields, decode as {} (skip all) ok
213 fields, decode as {} (skip all) IDL error: byte read out of buffer
213 fields, decode as the full Big (skip none) — control ok

Expected

Decoding a Candid record into a subtype that omits fields should skip the extra fields and succeed, regardless of how many fields are skipped. The encode/decode round-trip of a legal value should never trap.

Notes

  • Reproduces under both enhanced orthogonal persistence (default, memory64) and --legacy-persistence (wasm32), at the same 213 boundary.
  • Independent of the skipped fields' value type — observed identically with Nat and Nat8 fields, and independent of the field payload sizes.
  • Only the field-skipping path is affected; decoding the value into its full type is fine, which rules out the encoder.

Environment

  • moc source 1.14.1-42-ga7139f0719
  • wasmtime 45.0.2

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions