tables: widening on read, the refusal reasons, ill-formed text and comments (#532) - #592
Merged
Merged
Conversation
…text The `widened` counter is the sixth report member and its status line goes. `TableRefuseReason` is a NATIVE enum per target, carried on each language's standard error path, and the C++ reference now carries it on Open, BlockOpen and LoadMeasure's -1, so the three "OWED, not emitted" lines go with it. The reason is written on the refusal path only, which is what makes a successful open cost nothing. Comments are accepted in the text form on read and never written. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…med text The oracle counts `widened` where a kind grew since the writer, at a field, an arm, an array element and a map key, for the two integer ladders and f32 into f64, once per field and once per map. A kind 12 payload that is not well-formed UTF-8, or carries a zero byte, is damage: the field reads its declared default, one malformed counts, and a clamp cuts at a code point boundary. Comments are read in the text form and never written, an unclosed block comment malformed. Reserved kind 34 is refused as damage by name. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every unit carries TableRefuseReason, and Open, BlockOpen and LoadMeasure name the first failing clause in section 7's order, bad_alignment ahead of both truncated clauses, the base's alignment last because it is the one clause that reads nothing out of the file. Every block prologue word is read bytewise so that ordering holds. The widening branch lives inside the kind-mismatch branch a reader already takes, so a payload under the declared kind never reaches it. Ill-formed kind 12 text is refused at a field, an arm, a map key and a *string record, with the clamp at a code point boundary. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The report spelling grows a sixth counter, the reports pins move with it, and the wire fuzzer gains a widening strategy over arms, elements and keys and a text strategy over every kind 12 position. Two new surfaces, cook-reason and block-reason, pin one row per reason over the forgery fixtures. The json hostile tree gains the comment cases, accepted and refused. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts: # internal/codegen/cpptable/arms.go # internal/codegen/cpptable/codecs.go # testdata/conformance/tables/MANIFEST.txt # testdata/conformance/tables/reports.txt
…ts pins Every LoadMeasure now takes the reason out-parameter, so the wire fuzzer's leg carries the unit's own TableRefuseReason as a template parameter. The length negative control changes what it quotes: the content rule reads a kind 12 payload as it arrives, over the whole of L, so a leg that lost room(len) walks off the buffer and dies on the mutant where it used to clamp a neighbour's bytes. The arm evolution row moves from one kind_mismatch to one widened. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…wn prefix BlockOpen's truncated and unaligned_base are pinned in test/tables, beside the match that writes nothing, because each is a clause over the buffer the CALLER passed and no patched word of an image reaches it: the cross-language battery keeps its eleven rows and every port stays green on them. The zero-cost scan sanctions TableRefuseReason by its whole spelling, since TableRef is a prefix of it and the extraction takes the longest alternative. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…wn clauses A form byte this build does not carry makes SceneLoadMeasure -1 with unknown_form, and a form it does carry writes nothing at all beside the size. BlockOpen's own readings are pinned where each is actually reachable: a null base and a length under the prologue by their values, a length whose arrays no longer fit as bad_layout, and the base's alignment over a WHOLE image copied to an unaligned address, which is what it takes to reach the last clause. The remaining widened lines in USAGE, VERSIONING and COMPETITION go. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… enum The generated C++ sources gain the refusal enum, the widening helpers and the text helpers, so testdata/golden/tables is re-pinned deliberately. NOT ONE WIRE GOLDEN MOVES: this changes what a reader does with bytes it would have skipped, never what a writer puts on the wire. The Go zero-cost test strips TableRefuseReason before its scan for the same reason the Makefile's does, and the pack corpus reads the sixth counter. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The arm's own copy of the backward search goes, and the search itself reads as slices.Backward. Nothing about which lengths the text pass aims at moves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The declared-maximum comment moved ahead of its check when BlockOpen started naming its refusals, so the sabotage's address range ran to the end of the file. It brackets the comment and the check in the order they are written. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TableCookOpen's last clause names its reason now, so the sabotage's anchor follows it. What the control plants and what it proves are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The text form could put a raw ill-formed byte into storage, and the wire it then wrote was one this PR's reader calls malformed. Section 16.3's rule now runs at the point the defect enters, in the engine and in the C++ walk both: a byte in a string body that is not part of a well-formed sequence reads as one U+FFFD, exactly as a lone surrogate escape already did, so storage the text form built is storage the wire can carry. The str-illformed-at-bound row moves to one clamped, because three bytes where one stood pass the bound. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The two tests that pinned a raw ill-formed byte riding into storage now pin what replaces it, and the text form is byte-stable from the first lap rather than after one. NOT ONE WIRE GOLDEN MOVES. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts: # internal/codegen/cpptable/pointers.go # ir/tablewire.go # test/conformance/harness/wireframe.go # test/tables/wire_fuzz_main.cpp # testdata/golden/tables/arms/CarryTable.h # testdata/golden/tables/arms/GateTable.h # testdata/golden/tables/arms/NestTable.h # testdata/golden/tables/arms/RingTable.h # testdata/golden/tables/blobs/AssetsTable.h # testdata/golden/tables/lists/HoldersTable.h # testdata/golden/tables/lists/MigrateTable.h # testdata/golden/tables/lists/ReportTable.h # testdata/golden/tables/lists/SaveTable.h # testdata/golden/tables/lists/SharedTable.h # testdata/golden/tables/maps/DepthTable.h # testdata/golden/tables/maps/FleetTable.h # testdata/golden/tables/maps/RowsTable.h # testdata/golden/tables/pointers/GraphTable.h # testdata/golden/tables/pointers/MarksTable.h # testdata/golden/tables/stream/StreamTable.h
…he element and the map key §3.3 holds §4's evolution rows to the file form's word, and the widening row was the one the message reader did not carry: an announced kind below this reader's on the same ladder was met as a kind mismatch and skipped. Both engines now take it. The payload already rode at the width the announcement states, so the branch sits inside the mismatch branch the reader already took and the matching path pays nothing. The two shapes the announced width does not settle on its own are handled beside it: f32 into f64 carries a NaN's payload on the bits rather than through the hardware conversion, and a narrow integer into a 128-bit declaration is sign or zero extended before this reader's own bound meets it. A map counts ONE widened at its key however many entries carry it, and an array ONE for the field however many elements it holds. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…use order and the prose pass The used extent is DERIVED from the arrays, so BlockOpen reads every triple before it compares the extent to the caller's bytes. §19.2 listed the two the other way round in both places it lists them, and the page now says the order the arithmetic forces and why. That clause's own reading joins the cross-language surface through the extent column rather than a patched word: block_extent_padding claims one byte less than block_render's used extent takes in rounding, on the precedent cook_claim_one_short set. unaligned_base stays C++-only, because it is a clause over the ADDRESS a caller passes and a manifest row hands a driver a path. The C++ BlockOpen gate gains the reading beside it. blob_over_size_cap is reachable without a four gigabyte input: <Root>NodeStorage is a pure function of a type id and a length, so the test hands it one past the cap and one at it. data_cycle is the one value no call writes today. The ruling is that it gets a carrier rather than losing its name: Measure and CookMeasure take the same out-parameter LoadMeasure takes, and threading it through the pack walk is a named follow-on. The file measure answers unknown_form for any byte that is not the file form, form 2 included, and the page now says so beside the value. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ument stops The wire fuzzer's widen pass has no purchase on form 2: a body carries no kind byte, so the kind a reader compares is the announcement's, which both engine and leg read from their own unit. A widening mutant would have to hand both sides a forged announcement and the driver's protocol carries a body. The row is held by a peer whose declaration has moved instead, and the page and the harness both say so. The block padding divergence is filed as schema#598 and the manifest comment names the five ports and cross-references #387. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rust, C#, Java, JavaScript and Dart raised a short extent claim to the image's own length, so BlockOpen's truncated clause over the caller's bytes was unreachable in five of nine languages and block_extent_padding answered open there against the reference's refuse. Each now allocates the claim and copies only what fits, which is what the comment in each already said. C# was copying bytes.Length into a buffer sized by the claim, and Dart was doing the same through setRange, so both carried a real overrun behind the clamp. Every port refuses the row now, and the manifest comment records what happened rather than a divergence that no longer stands (schema#598). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 6, 2026
gafferongames
added a commit
that referenced
this pull request
Sep 6, 2026
…the wire's own length (#621) * tables: a clamp answers within its bound, and the text runtime takes the wire's own length Certification's test (ubuntu-latest) job has been red since 28133b4 (#592) on the length negative control, which removes r.room( len ) from a copy of the emitter and requires the wire fuzzer to go red because the leg DIED on the mutant. On Ubuntu it went red on a report difference instead, and the leg's heap was corrupted: munmap_chunk(): invalid pointer. Mutant 629 of seed root_full spells the string field's L as 0xFFFFFFFFFFFFFFFF. #592 added two text helpers that took that length as a signed count, and (int64_t) 0xFFFFFFFFFFFFFFFF is -1. TableUtf8Clamp opens with "if ( length <= bound ) return length", -1 is under every bound, the caller widens the answer back to SIZE_MAX, and the field's memcpy runs at SIZE_MAX. ASan on the sabotaged leg, replaying that mutant, calls it negative-size-param (size=-1) at the field's memcpy. On this Air that copy faults and the leg dies, which is the red the control names; on glibc it writes outside the destination, corrupts the neighbouring chunk header, returns, and the leg reports before free aborts. A LENGTH IS A 64-BIT NUMBER (docs/SPEC-TABLES.md §3), so TableUtf8Valid and TableUtf8Clamp take it as one, and the clamp's answer is never above its bound. The string field read and the string map key drop the casts that narrowed it. The sites passing a reader's own span are non-negative by construction and are unchanged, and the Go oracle takes a slice and cannot express the defect. Nothing changes in a clean build: room( len ) already bounded every length these helpers see, which is what the negative control exists to prove. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tables: the length control names the red the missing fit check now produces The control removes `r.room( len )` and required the wire fuzzer to go red because the leg DIED on the mutant. With the clamp answering within its bound no leg dies there: the first mutant that exposes the loss is the length pass's 0xFFFFFFFFFFFFFFFF on root_full, mutant 629, where the sabotaged leg takes the payload over bytes the mutant never carried, steps its cursor by a length the body never had, and reports a kind mismatch the oracle does not. That red is an in-bounds deterministic computation, the same on every allocator, where the death it replaces was a wrapped memcpy size that faulted on one libc and corrupted the heap on another. The named reason becomes the report difference, and the comment says what the sabotage now does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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.
Closes #532. The kinds-and-rules page lands in the C++ reference, the oracle
and the tool: the
widenedcounter,TableRefuseReasononOpen,BlockOpenand a variable root's load measure, ill-formed kind 12 text asdamage, comments read and never written in the text form, and reserved kind
34 refused by name. Five
BACKEND STATUS: OWEDlines are deleted, one perclaim this makes true, and so are the widening caveats in
USAGE.md,VERSIONING.md,COMPETITION.md,COMPARISON-TABLES.md,FAQ.mdandTUTORIAL.md.origin/mainis merged in, so this branch carries #557's bitpacked messageform, #593 and #591.
What lands
1.
widened, the sixth report member. An integer kind read into a widerone of the same signedness, and
f32intof64, decode EXACTLY at the wirekind's width and count
widenedonce per field and once per map. The branchis emitted at every site this wire compares kinds: a field's own kind, an
arm's, a positional array's element kind, a keyed body's, a list's, and a
map's key kind. The arm evolution row
a1_arm_moved_width_as_a2moves fromone
kind_mismatchand aNoneunion to onewidenedand the value, andthe manifest's pin moves with it.
1b. And the same row on the MESSAGE FORM, which §3.3 holds to the file
form's word ("NO EVOLUTION ROW OF §4 MOVES"). After the merge the message
reader compared kinds at three sites with no widening branch and the oracle
did the same, so the page's sentence was unmet. Both engines now take it, at
the field, the arm, the positional array's element and the map's key. The
payload already rode at the width the ANNOUNCEMENT states, so the branch sits
inside the mismatch branch the reader already took and the matching path pays
nothing. Two shapes the announced width does not settle on its own are handled
beside it:
f32intof64carries a NaN's payload on the bits rather thanthrough the hardware conversion, and a narrow integer into a 128-bit
declaration is sign or zero extended before this reader's own bound meets it.
2.
TableRefuseReason. One NATIVE enum per target, a C++ enum here, inevery unit, carried on each language's standard error path: an out-parameter
beside the null in C and C++, never an exception.
Open,BlockOpenandLoadMeasurename the FIRST failing clause in §7's order,bad_alignmentahead of both
truncatedclauses and the base's alignment LAST because it isthe one clause that reads nothing out of the file. Every block prologue word
is read bytewise so that ordering holds. It is written on the refusal path
only: a match writes nothing, which is what makes the successful open cost
nothing.
3. Ill-formed kind 12 text is damage. A payload that is not well-formed
UTF-8, or that carries a zero byte, reads the declared default and counts one
malformed, checked AS IT ARRIVES and before the reader's own bound, at afield, an arm, a map key, an array element and a
*stringrecord. A clampcuts at a code point boundary, so a clamp can never invent ill-formed storage.
4. Comments in the text form, read and never written:
//runs to the endof the line or of the input,
/* */to its closing delimiter, which does notnest, and an unclosed
/*is malformed on the terms an unclosed string is.Seven
json-hostilerows, five accepted and two refused.5. Reserved kind 34 is refused as damage by name, in the oracle's
skipand in
TableReader::skip, exactly as 35 or 200 is.The cost rule, and the sitting
The sitting was re-run on the MERGED unit, because #557 moved
MeasureBody,SaveBodyandLoadBodyand the artifact that merges has to be the onemeasured.
The sitting. Apple M2 MacBook Air, 8 cores, macOS 26.6.2, Apple clang
21.0.0,
-O3 -DNDEBUG -fno-rtti -ffp-contract=off, 2026-09-05 23:15 local,one-minute load average 2.35 read with
uptimein its own command beforethe run, swap 0.00M in use. Seven alternations of four arms round-robin in
one process each, so any drift in the box lands on all four. It is a pairing
check on a shared interactive machine, not a publishable number.
Four arms, one
bench/tables/cpp/table_main.cpp, one set of flags.beforeisorigin/main's committed generated bench unit, 7,912 lines.afteris this branch's, 9,157.layoutisorigin/main's with this branch's ADDED RUNTIME pasted in andnothing else, 8,063: the refusal enum and the widening and text helpers, none
of them reached from the bench's codec. It carries the translation unit's
GROWTH without the behavior, so whatever it does to the write arm is what the
layout did. The 1,094 lines between it and
afterare emitted BRANCHES, notruntime, and every one of them sits inside a kind-mismatch arm.
plantedis the NEGATIVE CONTROL: the widening predicate moved ONTO thematching path and made a real call,
if ( kind != N )becomingif ( TableKindWidens( kind, N ) || kind != N )withTableKindWidensnolonger inline. It answers the same thing at every site and pays for the
predicate whether or not the kind moved. 59 sites.
The tables bench, M msg/s, higher is better
The read arm is unchanged: 0.274 to 0.273 best and 0.273 to 0.271 median,
a 0.7% median move against per-run spreads of 0.4% to 1.1% on that arm.
THE CONTROL IS RED. Planting the predicate on the matching path costs
10.1% of best and 9.8% of median on the read arm, 0.273 to 0.245 both ways,
so the instrument sees a cost of the size this feature would have had if it had
been put where the payload under the declared kind runs. It is not there: the
widening branch lives inside the
kind != Nbranch a reader already takes,which today skips the payload, and the generated text shows it. The control
leaves the WRITE arm alone, 0.901 to 0.904 best, which is what says it is
aiming at the read path and nothing else.
The write arm's arms sit within their own spread (0.887, 0.897, 0.887,
0.898 median against a 6.5% worst per-run spread on that arm), and
layoutlands on
beforeto three figures, which is the readingbench/LOCKalreadygives: a byte-identical source measures differently and the unit's size is what
moves it.
The packet bench
generated/bench/cppandgenerated/bench/care byte-identical toorigin/mainon the merged branch, verified withgit diff origin/main HEAD --over both trees, which comes back empty. This PR touches no packetemitter, so the type wire's read and write paths are unchanged by
construction rather than merely within noise, and that is a stronger statement
than a measurement of them would be.
Gates, each with its control quoted red
make tables-wire-fuzz: 129 seeds over 42 roots, 121,984 enumerated +20,000 random = 141,984 mutants, 0 divergences against the Go oracle,
including the widening pass (a widening and its reverse at every integer
and
f32kind byte, over fields, arms, elements and keys) and the textpass (a truncated sequence, an overlong encoding, a lone continuation, a
surrogate, and a zero byte at the front, the middle and the end of every
kind 12 payload).
with the widening predicate planted off:
make tables-wire-fuzz-length-negative-control: RED, and it changeswhat it quotes: the content rule reads a kind 12 payload as it arrives, over
the whole of
L, so a leg that lostroom( len )walks off the bufferinstead of clamping a neighbor's bytes.
harness: FAILED after 629 mutants: the leg died on the mutant (EOF)make tables-zero-cost: green, and its control RED:negative control: a planted node symbol turns the zero-cost scan RED, and the reserved id alone does notThe scan now sanctions
TableRefuseReasonby its whole spelling, becauseTableRefis a prefix of it and the extraction takes the longestalternative.
make conformance: every registered surface passes in all ninelanguages,
cook-reason21/21 andblock-reason12/12, andforgeryis now12/12 in every port rather than 11/12 in five of them.
test/tables/block_main.cpppinsBlockOpen's own readings:okuntouched on a match,
unaligned_basefor a null base and for a WHOLE imagecopied to an unaligned address,
truncatedfor a length under the prologue,bad_layoutfor a length whose arrays no longer fit, andtruncatedfor alength that stops INSIDE the used extent's own padding.
test/tables/main.cpppinsunknown_formandblob_over_size_cap.Page rulings a builder made, for the owner to keep or overturn
Each is a sentence the page did not carry, written onto it because the code
could not be written without answering it.
answers
unaligned_baseand a buffer shorter than the header answerstruncated. Neither is a fact about the file, and the page named no valuefor either.
BlockOpen, which owes them for the samereason and had the same silence.
-1for a trailer that cannot be read whole writes nothing." Damageis not a refusal, and the reason enum is the refusal's vocabulary, so a
measure that fails on damage leaves the caller's own value standing.
TableRefuseReason, replacing "a unit withneither construct carries neither": every unit's cook
Opennames itsrefusal in it, so every unit needs the enum whether or not it has a pointer
or a block.
bad_layoutclauses run BEFORE the used-extenttruncatedclause, becausethe used extent is derived from the arrays and has nothing to say until
they agree. The page listed them the other way round in both places it
lists them.
unknown_formis any byte that is not THIS CALL's form, form2included at a file measure. A build that carries the message form carries
it through the message surface, and a batch handed to a file root is a form
its file measure does not read.
Loadbeside it still distinguishes thetwo, answering
message_form_as_filewhere the byte is2, because areport has room to say which and a
-1has one value.data_cyclegets a carrier rather than losing its name. It is refusedby
Measure,CookMeasure,Save,CookandLock, each of whichanswers a bare
-1orfalse, whileLoadMeasureis the only measurethat takes the out-parameter. An enum value no call can write is a case
that exists only in the vocabulary, so the ruling is that
MeasureandCookMeasuretake the same trailingTableRefuseReason *. Threading itthrough the pack walk is a named follow-on, not part of this row.
unaligned_baseis the one block value the cross-language surface doesnot carry, because it is a clause over the ADDRESS a caller passes and a
manifest row hands a driver a path. The page said one row per value. It now
says which one is held in the C++ gate instead and why.
What the page left silent, and what this had to decide
text introducing ill-formed storage only through a LONE SURROGATE ESCAPE,
which both readers already mapped to
U+FFFD. A raw byte reached storageintact, and the wire this PR then wrote was one this PR's own reader calls
malformed, soschema packemitted a wire no conforming reader accepts.§16.3's own words ("the rule underneath both is one rule") are applied at
the point the defect ENTERS: the read replaces it with one
U+FFFD, in theengine and in the C++ walk both, counted as nothing and clamped at a code
point boundary like anything else. The page now says so.
str-illformed-at-boundmoves to oneclamped, and the text form isbyte-stable from the FIRST lap rather than after one.
This decision STANDS pending your yes, and nothing about it moved in
this round.
and is NOT closed here. §16.3 states that a narrow field's interior zero
byte is a code point JSON has an escape for and "the text round-trips it
exactly", and §3 says a kind 12 payload carrying a zero byte is damage.
Those two sentences disagree. Filed as Page contradiction: a JSON unicode-zero escape in a string(N) body, round-tripped by §16.3 and damage by §3 #594 for your ruling. No corpus
row reaches it today, so nothing is red, and nothing here guesses at it.
TableRefuseReasonand itsvalues and does not say scoped or unscoped. Landed as an UNSCOPED enum at
namespace scope, matching
TableMessageReasonbeside it, with every valuename claimed in §11 through
internal/tablenamesso no declaration cancollide with one.
bad_layoutclauses. §19.2 lists "a pitch, acount, an offset or an extent" under one value, so the order among them is
unobservable. Landed as pitch, count, offset floor and alignment, offset
past the caller's bytes, rows past the extent.
with one
kind_mismatch, and the page does not say whether awidenedcountedat an earlier key is retracted. Landed as KEPT: the counter names an event,
not a surviving value.
unknown_formfrom a MESSAGE measure with no announced vocabulary. Thepage names the form byte and not the announcement. Landed as writing
nothing: an unannounced connection is §3.3's refusal, not §6.5's.
A divergence found, filed, and closed in the same round
schema#598.
BlockOpen'struncatedclause over the CALLER's bytes, ablock whose used extent's padding runs past the buffer it was handed, was
refused by the reference and opened by five ports: C#, Dart, Java,
JavaScript and Rust.
docs/SECURITY.mdnames a cross-language acceptancedivergence a security bug on its own terms, so it was filed rather than
absorbed.
The new manifest row
block_extent_paddingis what found it, on the precedentcook_claim_one_shortset: no patched word, the extent column alone, overblock_render, whose greatest array end is 2784 in a 2816-byte image, so aclaim of 2815 covers every array and not the padding.
The READERS were never the problem: all nine generators emit the clause. The
five drivers were, each raising a claim SHORTER than the image to the image's
own length, so the input had never been expressible in them. Two of them were
worse than that: C# copied
bytes.Lengthinto a buffer sized by the claim andDart did the same with
setRange, so both had a real overrun waiting behindthe clamp. Each now allocates the claim and copies only what fits, as the C++
reference, C, Go and Elixir already did, and all nine refuse:
Closes #598. #387 stays open for the other half of the same driver work, the
pointer column, which
unaligned_baseneeds.Named follow-ons
fact about the form rather than a gap in the pass: a form-2 body carries no
kind byte at all, so the kind a reader compares is the ANNOUNCEMENT's, which
both the engine and the leg read from their own unit. A widening mutant
would have to hand both sides a forged announcement, and the driver's
protocol carries a body. §4's widening row on this form is held by a peer
whose declaration has MOVED instead, which is the shape every other §4 row
on this form is held by. Said on the page and in the harness.
data_cycle's carrier (ruling 7 above):MeasureandCookMeasuretake the out-parameter, threaded through the pack walk.
Two controls this PR had to re-aim
Each still goes red for the reason it names, and each moved because the code
it brackets moved, not because it stopped holding.
tables-wire-fuzz-length-negative-controlquotesthe leg died on the mutantrather thanthe report differs: the content rule reads a kind 12payload over the whole of
L, so a leg withoutroom( len )walks off thebuffer instead of clamping a neighbor's bytes.
BLOCK_FUZZ_SED_CPP_maximumand thecook-open-walk-cppsabotage anchor onthe lines where the declared-maximum check and the alignment refusal now
sit.
make testis green whole on this branch.