CHANGES:
Added
Wire.Expr.land64is an int64 bitwise AND for masking a full-widthuint64
field inside a constraint, and~self_int64/Field.int64now accept a
map-decoded uint64 field. A sign-magnitude offset bound such as a bsdiff
seek (land64 self mask <= max) is now expressible and projects to a 3D
refinement EverParse verifies (#227, @samoht)
Changed
-
The standalone
c/archive (3dmode) now builds and installs in every dune
context through that context's own toolchain, so a cross build produces and
installs a target-native verified parser instead of skipping the C. The build
uses%{ocaml-config:c_compiler}, theocaml-configpartial linker, and the
binutils that compiler resolves (-print-prog-name), so a crossccfinds
the target'sobjcopy/ar.EverParseEndianness.hgains a freestanding
__BYTE_ORDER__/__builtin_bswap*branch so it compiles for an OS-less
target (a unikernel defines neither__linux__nor__APPLE__). Only C
regeneration and theagreedifferential test stay host-gated (#231, @samoht) -
uint32/uint32benow decode toOptint.tanduint63/uint63beto
Optint.Int63.trather than a nativeint, so a value with bit 31 (or the
high half) set is no longer silently truncated on a target whoseintis
narrower than 63 bits (js_of_ocaml, wasm_of_ocaml); a TCP sequence number now
round-trips there. Read such a field withOptint.to_int/Optint.to_int32;
auint32used as a size parameter must becomeint32be(#226, @samoht) -
Decode errors are redesigned.
parse_erroris now a{ at; field; kind }
record instead of a flat variant:atis the failing field's byte offset,
fieldthe root-to-leaf path of field names to it, andkinda closed
error_kind(Unexpected_eof,Invalid_enum,Invalid_tag,
Missing_terminator,Non_zero_padding,Value_out_of_range,
Constraint_failed), so a failure deep in a nested struct is both locatable
and matchable.Constraint_failed of stringbecomes
Constraint_failed { which; value }, naming the predicate that failed and
carrying the offending field's value.Validation_erroris removed
(Codec.validateand the_exndecoders raise the singleParse_error), and
the type gainsequal_parse_error/compare_parse_error,pp_error_kind,
and publicparse_error/eofconstructors. Match one.kind, reade.at,
replaceValidation_errorwithParse_error, and wrapWire.parse_errorin
your own variant for domain errors (#219, @samoht) -
Decoding a record codec with 17 to 32 fields no longer allocates a
short-lived closure on each decode: the closure-free decode ceiling that
1.0.0 raised to 16 fields now extends to 32. Real protocol headers cross the
old limit routinely, such as an 18-field TCP header with its flag bits broken
out, or telemetry and IPv4 headers in the high twenties, which now allocate
only the record they return. A codec wider than 32 fields keeps the recursive
fallback (#214, @samoht)
Fixed
-
A standalone
Wire_3darchive no longer exposes its raw<Base>Validate*
validators to C callers. Those entrypoints skip aStartPosition <= InputLengthbound check, so a direct caller passingStartPosition > InputLengthunderflowed the read span and went out of bounds. The install now
ships only the checked<Base>Wrapper.hheader (not<Base>.h), and the
archive build localizes every symbol except the<Base>Check<Codec>wrappers,
so the raw validators are neither declared nor linkable; the wrapper validates
from position 0 and is the safe public API (#228, #229, @samoht) -
Codec values are now safe to share across domains: their validation scratch
and parameter backing are per-domain, so encoding, decoding, or validating one
codec concurrently no longer corrupts the result (#223, #224, @samoht) -
A generated FFI parser (
parse buf off) now raisesInvalid_argumentwhen
offis negative or past the end ofbuf, instead of reading out of bounds.
The C stub computed its length asBytes.length buf - offin unsigned
arithmetic, so an out-of-rangeoff(which can carry a length or offset field
parsed from untrusted input) underflowed the length into a huge span and
pushed the read pointer past the buffer before the validator ran. An in-range
offis unaffected (#222, @samoht) -
A non-zero byte in an
all_zerospadding field now reports the same error
whether the field is decoded through a struct (Codec.decode/
Codec.validate) or directly (Wire.of_string). The struct path used to
report a stringlyConstraint_failedthat dropped the byte offset while the
direct path reported the typedAll_zeros_failedwith the offset; both now
reportAll_zeros_failedcarrying the offset (#220, @samoht) -
A
casetypewhose discriminant matches no case now fails with the typed
Invalid_tagcarrying the tag value, the same class as an out-of-range lookup
index, instead of a stringlyConstraint_failed(#220, @samoht) -
A non-integer field referenced where an integer is required (a schema mistake,
such as a float used as a length) now raisesInvalid_argumentrather than a
parse error, keeping schema errors distinct from malformed input (#220,
@samoht)