# C++ QuickFIX replay callback buffer lifetime

Both C++ QuickFIX file profiles now reacquire the pending message after a gap
callback. Previously, a callback that read another stored message could make
replay deliver that other payload under the pending message's sequence number.
The correction adds no lock or allocation, and performs an extra read only
when a found message follows a reported gap.

## Reproduced corruption

Baseline source is ff044c85b with the new regression fixture and test wiring
only. Store sequence 2 as `pending`, sequence 3 as `x`, and replay 1 through 2.
The missing sequence 1 produces OnGap(1, 2). Its callback reads sequence 3;
OnMessage(2) then receives `xending` rather than `pending` in both formats.
Both commands abort on the payload assertion. This is a driven defect, not
just the earlier source-traced coordination request.

FindOutbound returns a view into the store's shared read buffer. Replay read
sequence 2 before calling OnGap, so the callback's read overwrote bytes that
Replay had not yet delivered. The old length remained attached to those bytes.
This does not demonstrate a defect in the classic session's resend path, which
does not call this replay API.

## Correction and regression coverage

After an accepted gap callback, Replay calls FindOutbound again before handing
the view to OnMessage. A callback that replaces the pending record therefore
delivers its current payload and length. If a callback clears or closes the
store, reacquisition fails and replay returns false without delivering a stale
view. A callback that rejects the gap stops immediately, without the extra read.
Contiguous replay does not gain another read.

The same shared fixture runs in both physical-store suites. Each format covers
seven callback actions with one-byte and 200-byte other payloads: read another
record, nested replay, replace the pending record, cancel the gap, clear the
store, close the store, and cancel message delivery. That is 14 scenarios per
format. These are single-threaded callback lifetime tests, not permission to use
these owner-thread stores concurrently or to retain a view across further store
operations.

## Verification and evidence

Both physical-store suites, protocol resend/session tests and real-socket tests
pass with GCC 11.5 and Clang 21.1 in both open and development include layouts:
16 successful suite executions. Both physical-store suites also pass with
AddressSanitizer, UndefinedBehaviorSanitizer and leak detection. Real pinned
QuickFIX C++ and QuickFIX/J handoff/crash-recovery smokes pass without skips.
Export scrub reports five changed engine files and zero findings.

Evidence is retained in
`~/archive/libhft/quickfix-replay-callback-review-20261003/`: baseline source pin,
test patch and fixture, failing payload diagnostics, verification source pin
and patch, five source hashes, compiler versions, scripts and complete logs.
The fixture copies retain the untracked new header alongside each patch.

Functional verification used the CPU-slot helper. The isolated pool was used
for the final tests and permits shared jobs to overlap; no latency measurement
or improvement is claimed. No Windows run, full correctness sweep, NIC test,
or Java/Rust/.NET code change is included in this correction.

## Follow up scope

The RAM and mmap replay implementations also hold a view across a gap callback.
Ordinary reads there do not overwrite a shared file-read buffer, so this exact
reproducer does not apply. Callback-time reset, close or ring replacement needs
its own reproductions before drawing conclusions or changing those paths.
The separately reproduced .NET fixture false-pass remains with its owner.
