Skip to content

fix: address compiler findings from the 0.14 audit - #452

Merged
rkalis merged 5 commits into
nextfrom
fix/compiler-audit-findings
Sep 25, 2026
Merged

rkalis merged 5 commits into
nextfrom
fix/compiler-audit-findings

Conversation

@rkalis

@rkalis rkalis commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Fixes the remaining compiler findings from the 0.14 audit (follow-up items 1, 2 and 7.1, and the early return TODO from the first review's item 6).

Changes

  • LockingBytecodeNullData push opcodes: the push opcode of a chunk was built from OP_SIZE, which is a signed VM number. Empty chunks therefore got no push opcode (a bare 6a instead of the SDK's 6a4c00), and chunks of 128-255 bytes got a malformed 4c <size> 00 prefix. The generated script now matches encodeNullDataScript() (and so addOpReturnOutput()) for every chunk size up to 255 bytes:
    • Chunks with a value known at compile time (hex literals and string literals like bytes('memo')) are pushed together with their push opcode as a single constant.
    • Chunks with a length known at compile time (e.g. bytes20) are preceded by a constant push opcode.
    • Other chunks use a runtime check that converts the size to a single byte and prepends OP_PUSHDATA1 for empty chunks and chunks of 76-255 bytes.
    • All of these are smaller than before. Chunks whose size is known to be larger than 255 bytes are now a compile error (NullDataChunkTooLargeError).
    • This changes the bytecode of every contract that uses LockingBytecodeNullData.
  • Tuple reassignment narrowing: after require(x.length == 20), x, bytes rest = y.split(5); kept x typed as bytes20 while it held 5 bytes. Tuple reassignment targets are now checked against their current (narrowed) type, like plain assignments.
  • Odd-length hex literals: 0x123 was silently compiled to 0x1203 and is now a compile error. Test contracts that used odd-length literals were updated without changing their bytes.
  • Early return TODO: removed from EnsureFinalRequireTraversal, early and conditional returns are tracked in Consider allowing conditional returns (multi returns) in user-defined reusable functions #416 and Allow for passing through multiple return values from a function return #424.
  • Docs: LockingBytecodeNullData chunk encoding and release notes.

Tests

  • cashc: compile error fixtures for too large hex literal, string literal and bytesN chunks, odd-length hex literals and the tuple reassignment narrowing bypass, new tuple_reassignment_narrowing.cash and locking_bytecode_nulldata_chunks.cash fixtures, and updated fixtures for announcement.cash and the contracts whose hex literals changed.

yarn build, yarn test, yarn lint and yarn spellcheck pass.

🤖 Generated with Claude Code

- Fix LockingBytecodeNullData push opcodes for empty chunks and chunks of
  128-255 bytes, which did not match the SDK's OP_RETURN encoding. Literal
  chunks are now pushed together with their push opcode, and literal chunks
  larger than 255 bytes are a compile error
- Fix tuple reassignment bypassing bytes length narrowing, e.g.
  `x, bytes rest = y.split(5);` after `require(x.length == 20);`
- Make hex literals with an odd number of digits a compile error
- Remove the early return TODO in EnsureFinalRequireTraversal (tracked in #416 and #424)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cashscript Ready Ready Preview Sep 25, 2026 3:24pm UTC

Request Review

@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.76%. Comparing base (37bf465) to head (768508d).

Additional details and impacted files
@@            Coverage Diff             @@
##             next     #452      +/-   ##
==========================================
+ Coverage   88.63%   88.76%   +0.13%     
==========================================
  Files          61       61              
  Lines        4980     5012      +32     
  Branches      920      927       +7     
==========================================
+ Hits         4414     4449      +35     
+ Misses        436      433       -3     
  Partials      130      130              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…odes

String literal chunks (e.g. `bytes('memo')`) are pushed together with their
push opcode like hex literals, and chunks with a known length (e.g. bytes20)
are preceded by a constant push opcode. The push opcode is only computed at
runtime for chunks with an unknown length. Chunks whose size is known to be
larger than 255 bytes are a compile error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rkalis
rkalis merged commit d2e3593 into next Sep 25, 2026
5 checks passed

This branch was successfully deployed

1 active deployment
Preview — 768508da Deployed Sep 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant