fix(controller): stop SIGSEGV in WalCatchupEntry capnp encode (bug-1505)
controller_unit_test crashed deterministically in write_WalCatchupEntry (test_wal_catchup_append_term_fields_round_trip) -- the same bug class as bug-1504 (SnapshotData.internalState): this codebase's capnpc-c backend silently no-ops Data-field encoding in generated encode_XXX() composite helpers without zero-initializing the caller's local struct first, leaving an uninitialized capn_ptr written onto the wire. Confirmed zero production exposure before fixing: xce_wal_batch_encode_ raw()/wal_entry_to_wire() (request.c) never call the generic encode_WalCatchupEntry() at all -- they memset() their own struct and call write_WalCatchupEntry() directly with every field hand-set, so this was 100% test-only exposure (grepped every caller of the generic encode/decode pair; only the crashing test uses it). Fix mirrors bug-1504: WalCatchupEntry.payload (@2) and batchPayloads (@10) switched from Data to List(UInt8) in controller.capnp (new batchPayloadsLen @11 companion; payload reuses the existing wirePayloadLen @9), typemap.h's wal_catchup_entry_t field types updated, and request.c's extract_data_bytes() widened to take a raw capn_ptr (it already only used .p internally) so its call sites work regardless of which Data-shaped wrapper the generated accessor returns now. batchPayloads' single-top-level-blob shape confirmed this does not reintroduce bug-847's per-element cross-segment far-pointer loss -- that issue is inherent to per-element data regardless of Data vs List(UInt8) spelling. Strengthened test_wal_catchup_append_term_fields_round_trip with real payload/batchPayloads content assertions -- previously never exercised, since the test's src fields were left NULL. Verified: controller suite 3/3 (was 2/3, crashing), scheduler suite unaffected at 37/37 (unrelated schema area). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPPXeKSUXUqcqvzNXY1rzJ
This commit is contained in:
parent
829fbe41dc
commit
1fd467d072
7 changed files with 121 additions and 22 deletions
|
|
@ -385,8 +385,14 @@ struct snapshot_transfer_s {
|
|||
struct wal_catchup_entry {
|
||||
uint64_t lsn;
|
||||
uint8_t entry_type;
|
||||
xce_data_t *payload; /* legacy decoded field — broken for
|
||||
* raw bytes; kept NULL, do not use */
|
||||
/* bug-1505 fix: List(UInt8) now, not Data (see controller.capnp's
|
||||
* WalCatchupEntry.payload comment for the full root cause) — a real
|
||||
* uint8_t* + wire_payload_len pair via the generic codec, same shape
|
||||
* bytes_read/content already establish elsewhere. Still legacy/unused
|
||||
* by production (wal_entry_to_wire() in request.c deliberately never
|
||||
* sets it — see that comment); this genuinely round-trips now instead
|
||||
* of being a documented-broken placeholder, but nothing reads it. */
|
||||
uint8_t *payload;
|
||||
int n_entries; /* batch: number of sub-entries */
|
||||
struct wal_catchup_entry **entries; /* batch: array of sub-entry pointers */
|
||||
/* Raw WAL entry payload bytes — same pattern as repl_config_push_req_t.
|
||||
|
|
@ -421,15 +427,23 @@ struct wal_catchup_entry {
|
|||
* send; used on decode to slice this entry's bytes out of the TOP-LEVEL
|
||||
* container's batch_payloads blob (below). */
|
||||
uint32_t wire_payload_len;
|
||||
/* bug-847: generic decoded placeholder for wire field batchPayloads @10 —
|
||||
* same broken-for-raw-bytes limitation as `payload` above; kept NULL, do
|
||||
* not use. Only meaningful on the TOP-LEVEL container (never on a nested
|
||||
* sub-entry). The real bytes are hand-extracted by xce_decode() into
|
||||
* raw_batch_payloads/raw_batch_payloads_len below, then sliced per
|
||||
/* bug-1505 fix: List(UInt8) now, not Data (controller.capnp's
|
||||
* WalCatchupEntry.batchPayloads comment has the full root cause —
|
||||
* same class as `payload` above and SnapshotData.internalState,
|
||||
* bug-1504). Generic decoded field for wire field batchPayloads @10;
|
||||
* genuinely round-trips now via the generic codec, but still unused by
|
||||
* production — the real bytes are hand-extracted by xce_decode() into
|
||||
* raw_batch_payloads/raw_batch_payloads_len below (a separate,
|
||||
* already-correct code path this fix does not touch), then sliced per
|
||||
* sub-entry using each entry's wire_payload_len into that entry's OWN
|
||||
* raw_payload/raw_payload_len (so every consumer keeps reading
|
||||
* raw_payload exactly as before — this is purely a wire-transport fix). */
|
||||
xce_data_t *batch_payloads;
|
||||
* raw_payload exactly as before). Only meaningful on the TOP-LEVEL
|
||||
* container (never on a nested sub-entry). batch_payloads_wire_len is
|
||||
* its own maplistcount companion (wire field batchPayloadsLen @11) —
|
||||
* distinct from raw_batch_payloads_len below, which belongs to the
|
||||
* separate hand-rolled extraction path. */
|
||||
uint8_t *batch_payloads;
|
||||
uint32_t batch_payloads_wire_len;
|
||||
uint8_t *raw_batch_payloads;
|
||||
size_t raw_batch_payloads_len;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue