test: mutation-harden LibMemoryKV overflow boundary coverage - #17
Conversation
Mutation testing of src/lib/LibMemoryKV.sol surfaced two surviving mutants on the MemoryKVOverflow boundary check (`pointer > 0xFFFF`): - `>` -> `>=` : SURVIVED - `0xFFFF` -> `0xFFFE` : SURVIVED The existing `testSetOverflow` only exercises the over-boundary case (an insert forced to `0x10000` reverts). Nothing asserted that an insert landing on the MAXIMUM valid 16-bit pointer (`0xFFFF`) is ACCEPTED, so both off-by-one mutations of the boundary went unkilled. Adds three tests-only boundary cases (no source/bytecode change): - max pointer 0xFFFF accepted (no revert; exact pointer encoded in kv) - 0xFFFE accepted (guards the boundary from below) - 0x10000 reverts with the exact overflowing pointer payload All other get/set/toBytes32Array behaviors (slot spread, pointer stride, key/value placement, length tracking, bisect leaves, masks) were already killed by the existing suite. This hardening also protects the future 16->32-bit pointer rewrite (issue #13). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 2 minutes and 50 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Reviewed 3b22a94: mutation-validated tests-only coverage for the LibMemoryKV max 0xFFFF pointer-overflow boundary (was untested; >/>= and >0xFFFE mutants survived); source byte-identical. LGTM. |
Group hardened:
MemoryKVOverflowboundary (max valid0xFFFFpointer acceptance)Scoped adversarial-mutation pass over the sole module
src/lib/LibMemoryKV.sol(
get/set/toBytes32Array). Tests-only —git diff src/is empty, nosource or bytecode change.
The mutation sweep found the suite to be very strong: every mutation across slot
spread, pointer stride, key/value placement, length tracking, allocation, and the
entire
toBytes32Arraybisect tree was already killed. The one weak spot wasthe overflow boundary in
set:testSetOverflowonly drove the free-memory pointer to0x10000and asserted arevert — the over-boundary case. Nothing asserted that an insert landing on the
maximum valid 16-bit pointer
0xFFFFis accepted, so off-by-one mutations ofthe boundary survived undetected. This is exactly the line issue
#13 (16→32-bit pointer
rewrite) will touch; pinning the boundary now protects that future change. This PR
does not implement #13.
Mutation matrix (behavior → mutation → killer)
pointer > 0xFFFF→>= 0xFFFFtestSetPointerBoundaryMaxAccepted(new)pointer > 0xFFFF→> 0xFFFEtestSetPointerBoundaryMaxAccepted/...BelowMaxAccepted(new)0x10000testSetOverflow+ new...OverflowReverts(exact payload)mod(...,15)*0x10*0x10→*0x20,15→160xFFFFwalk0x40→0x60mload(ptr)mload(ptr+0x20)ptr+0x20ptr+0x40exists := 10mod(...,15)15→16(get/set sync)0x400x60ptr+0x20ptr+0x40startPointer0(chain break)+2+10x600x40not(shl(...,0xFFFF))→not(0)shl(bitOffset,ptr)shl(0,ptr)shr 0xf0shr 0xe0testSaturatemask128,shr 0x90)New tests
testSetPointerBoundaryMaxAccepted— insert with free-mem-ptr at exactly0xFFFFmust NOT revert; asserts the pointer0xFFFFis encoded into akvslot and length is exactly
2.testSetPointerBoundaryBelowMaxAccepted— same for0xFFFE, guarding theboundary from below.
testSetPointerBoundaryOverflowReverts—0x10000reverts with the exactMemoryKVOverflow(0x10000)payload.(The accepted-case tests deliberately assert the
kvpointer encoding andnon-revert rather than reading the value back: a node placed at
0xFFFFlives inlow memory and may be clobbered, so the encoding/non-revert are the safe oracles.)
Verification
forge build: clean (Compiler run successful!; only pre-existingboolean-cstlint warnings from the source bisect tree / slow ref impl, unrelated to this PR).
forge fmt --check: clean.PASS on the restored baseline; source restored (
git diff src/empty).Remaining gaps checklist
MemoryKVOverflowfor the update path (updatesnever allocate, so they cannot overflow — currently a non-issue, but worth a
note if support larger pointers #13 changes allocation).
getround-trip at
0xFFFF(intentional —0xFFFFlow memory is clobberable).get/sethash-sync is covered only indirectly (bothmod(...,15)mutations are killed); no dedicated test asserting identical slot derivation.
testSaturatefuzz (which deterministically fills all slots via re-hashing); no
per-leaf deterministic unit test.
🤖 Generated with Claude Code