# SBE transport and shared-page review — 2026-10-14

This pass fixes six reproduced defect classes in the C++ shared-memory primitives,
Java mapped SBE ring, and .NET/Rust multicast helpers. It qualifies these paths,
not the whole FIX engine. Parallel source review used one session worktree; this
session's builds were serialized, capped at 16 jobs, and waited for foreign heavy
processes as well as the shared host lease.

## Changes and failure evidence

- **C++ shared-page initialization ownership.** Throwing layout constructors or
  initialization callbacks leaked the mapping, descriptor, exclusive lock, and
  unpublished segment name. A scoped owner now releases them on every failed
  path, preserves the original exception, and destroys a fully constructed but
  unpublished layout after callback failure. The name is copied before acquiring
  resources, so a callback that changes the caller's string cannot redirect
  cleanup to an unrelated segment. Existing segments survive failed attaches.
- **C++ shared-page alignment.** Readers and writers accepted page-aligned maps
  that did not satisfy a layout's stronger alignment. They now refuse them before
  construction or typed access, using the existing mapping-error result. Tests
  force aligned and misaligned real mappings for 8 KiB and 64 KiB layouts and
  verify resource/name ownership; existing ring-alignment controls remain.
- **C++ aliased slot payloads.** `ShmFrameSlot::SetPayload` wrote metadata before
  copying, corrupting sources stored in that metadata; overlapping payload ranges
  also reached `memcpy`. It now moves bytes before metadata stores, handles overlap,
  and avoids copying a message already encoded in its destination. Oversized
  inputs still leave the entire slot unchanged; empty/null input avoids a copy.
- **Java aliased mapped-ring payloads.** The forward byte loop corrupted overlap
  when destination followed source. Absolute bulk `ByteBuffer.put` preserves the
  payload for direct, heap, read-only, and mapped views, including overlap, while
  preserving positions and limits. This also removes per-byte bounds checks.
- **.NET/Rust multicast cross-delivery.** On Linux, different multicast groups
  sharing a port both received a packet sent to either group because the socket
  retained `IP_MULTICAST_ALL=1`. Receivers now disable that option during setup.
  Loopback tests verify both group isolation and same-group fanout. The receive
  hot path and wire format are unchanged. This controls multicast membership
  filtering; it does not promise to filter unicast packets sent to the bound port.
- **.NET multicast disposal.** Removing membership after the publicly exposed
  socket had already closed threw `ObjectDisposedException`, including on the
  second `Dispose`. Cleanup now tolerates that state and still closes the socket.

Initial regression source: `5bf3180a3`; additional slot and caller-name regressions:
`ab0b2b5a7`. The original page cases failed 13 assertions; the expanded three-case
fixture failed 19. Alignment had 17 passing controls and six failed page cases
(32 failed assertions). Slot alias tests failed 92 assertions across 99 exercised
source/length combinations. .NET failed all three new cases while its native guard
passed. Rust had one isolation failure and one fanout pass. Java had two overlap
failures and one bounded-source control pass. No baseline test was skipped.

## Qualification and evidence

Qualified source: `d5fb1ce665d87ac62c73236fcaeb1c1678d551d1`, based on `c5a6a6b0465bf41f4a81bd01a3e8c6f497c95116`.
All 25 stages passed. C++ ran the three regression programs normally and with
UBSan (no recovery), covering three exception cases, 23 alignment cases, 99 alias
combinations, and the existing frame-stream controls. The page smoke test also
passed with exceptions and RTTI disabled. All 91 CORE tags matched; the CORE
loopback FIX socket gate passed.

.NET passed 64 development and 61 open tests. Both native libraries were built in
their standard edition-specific locations and their required-library guards passed.
Rust passed 32 SBE tests in each edition. Java's standalone SBE Maven module passed
51 tests; it has no JNI dependency. There were zero failures, skipped tests, or
ignored tests. The changed-source export scan passed for all 11 code/test files.

Integration through `980a80d63c2b810e425206747b3459e14f118ae6` includes separate acceptance-test
fixture cleanup and FIXP metadata directory-durability fixes. All 11 transport
source/test files remain byte-identical to the qualified source. At integrated
pin `e5dd2285ececba15f31dd8f5bca2258f077cff2a`, six further stages rebuild both .NET native editions
and rerun the .NET/Rust SBE selections. .NET again passes 64 development and 61
open tests, including both native-loading guards; Rust again passes 32 per edition.
All six stages pass with zero failed, skipped, or ignored tests. The C++ transport
and standalone Java SBE dependencies are unchanged, so their original qualification
is retained. Both source pins and raw integration logs are archived.


## Focused Java copy measurement

Java 21, `-Xbatch`, pinned to logical CPU 2 on BEELINK2 (Ryzen 7 8745HS).
Seven alternating pairs per case, 200,000 warmup handoffs per variant/case,
and 200,000 measured handoffs per variant/pair. All 140 measured samples allocated zero thread bytes.

| Source | Bytes | Before (ns) | After (ns) | Median paired ratio |
|---|---:|---:|---:|---:|
| heap | 16 | 23.169 | 14.617 | 1.585× |
| heap | 64 | 29.922 | 16.245 | 1.871× |
| heap | 256 | 70.245 | 17.179 | 4.088× |
| heap | 1024 | 243.858 | 24.236 | 10.097× |
| heap | 4096 | 909.986 | 46.309 | 19.735× |
| direct | 16 | 20.499 | 14.785 | 1.386× |
| direct | 64 | 31.496 | 15.035 | 2.102× |
| direct | 256 | 78.206 | 17.266 | 4.575× |
| direct | 1024 | 265.817 | 23.333 | 11.318× |
| direct | 4096 | 1015.177 | 47.739 | 21.348× |


This is a warm, single-thread push/pop diagnostic through two mappings of a
four-slot ring. It excludes cross-core/process wakeups, network transport, and
whole-engine/session latency. Both variants run in one JVM with alternating order,
checked payload/checksum/cursors, zero drops, and measured per-thread allocation.
The process monitor must report no other heavy job during the measured invocation.

Evidence is retained outside Git at
`/home/yann/archive/libhft/reviews/2026-10-14-codex-review-transports-1014`:
baseline/qualified/published Git bundles, exact source snapshots, test scripts and
logs, .NET TRX and Java XML results, raw benchmark CSV and source hashes, process
monitoring, JSON summaries, and a SHA-256 manifest. This avoids adding bulky logs
to every checkout. The existing live-ring recreation policy is unchanged.
