Bound infrastructure payload string fallbacks

This commit is contained in:
Jan Petykiewicz 2026-04-18 13:52:18 -07:00
commit 1873db0b08
3 changed files with 51 additions and 33 deletions

View file

@ -3966,6 +3966,7 @@ fn build_infrastructure_asset_trace_report(
"direct disassembly now also shows 0x00493be0 iterating live-entry ordinals through 0x00518380(ordinal, 0), converting each ordinal to a live id, then resolving that live id through 0x00518140 before handing the resulting payload pointer to 0x0048dcf0".to_string(),
"direct disassembly now shows 0x00518680 loading the non-direct collection header, tombstone bitset, and live-id-bound-scaled 12-byte tables for the non-direct path before 0x00493be0 starts iterating".to_string(),
"direct disassembly now also shows the shared child payload callback 0x00455fc0 opening 0x55f1, parsing three len-prefixed strings through 0x531380, opening 0x55f2, seeding the child through 0x455b70, dispatching slot +0x48, and then opening 0x55f3".to_string(),
"direct disassembly now also shows 0x00455b70 storing those three payload strings into [this+0x206/+0x20a/+0x20e], defaulting the second lane through a fixed literal when absent and defaulting the third lane back to the first string when absent".to_string(),
format!(
"current save-side probe reports {} embedded 0x55f1 rows with a third decoded string",
side_buffer
@ -3980,7 +3981,6 @@ fn build_infrastructure_asset_trace_report(
blockers: vec![
"how the payload streams reached through 0x00518380 -> 0x00518140 align with the embedded 0x55f1 name-pair groups and compact-prefix regimes surfaced by the save-side probe".to_string(),
"which tagged values inside each payload stream correspond to the child count, optional primary-child ordinal, and the per-child shared tagged callback sequence consumed by 0x0048dcf0".to_string(),
"whether the third 0x55f1 string parsed by 0x00455fc0 is absent on grounded saves, stored under a different framing than the current probe, or only populated on a narrower infrastructure subset".to_string(),
"which restored child fields or grouped rows retain the 0x38a5 embedded name-pair semantics before route/local-runtime follow-ons take over".to_string(),
],
},
@ -12546,6 +12546,26 @@ fn parse_save_len_prefixed_ascii_name(bytes: &[u8]) -> Option<String> {
Some(text.to_string())
}
fn parse_save_varlen_ascii_name_at(bytes: &[u8], offset: usize) -> Option<(String, usize)> {
let first = *bytes.get(offset)?;
if first == 0 {
return None;
}
let (len, header_len) = if first <= 0x7f {
(first as usize, 1usize)
} else {
let second = *bytes.get(offset + 1)? as usize;
((((first as usize) & 0x7f) << 8) | second, 2usize)
};
let start = offset + header_len;
let end = start.checked_add(len)?;
let text = std::str::from_utf8(bytes.get(start..end)?)
.ok()?
.trim_end_matches('\0')
.to_string();
Some((text, end))
}
fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, String)> {
let (first, second, _) = parse_save_len_prefixed_ascii_name_triplet(bytes)?;
Some((first, second))
@ -12554,42 +12574,22 @@ fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, Stri
fn parse_save_len_prefixed_ascii_name_triplet(
bytes: &[u8],
) -> Option<(String, String, Option<String>)> {
let first_len = *bytes.first()? as usize;
let first_end = 1 + first_len;
let first = std::str::from_utf8(bytes.get(1..first_end)?)
.ok()?
.trim_end_matches('\0')
.to_string();
let (first, first_end) = parse_save_varlen_ascii_name_at(bytes, 0)?;
let mut second_len_offset = first_end;
while matches!(bytes.get(second_len_offset), Some(0)) {
second_len_offset += 1;
}
let second_len = *bytes.get(second_len_offset)? as usize;
let second_start = second_len_offset + 1;
let second = std::str::from_utf8(bytes.get(second_start..second_start + second_len)?)
.ok()?
.trim_end_matches('\0')
.to_string();
let (second, second_end) = parse_save_varlen_ascii_name_at(bytes, second_len_offset)?;
if first.is_empty() || second.is_empty() {
return None;
}
let mut third_len_offset = second_start + second_len;
let mut third_len_offset = second_end;
while matches!(bytes.get(third_len_offset), Some(0)) {
third_len_offset += 1;
}
let third = bytes
.get(third_len_offset)
.copied()
.filter(|len| *len != 0)
.and_then(|third_len| {
let third_len = third_len as usize;
let third_start = third_len_offset + 1;
let text = std::str::from_utf8(bytes.get(third_start..third_start + third_len)?)
.ok()?
.trim_end_matches('\0')
.to_string();
(!text.is_empty()).then_some(text)
});
let third = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
.map(|(text, _)| text)
.filter(|text| !text.is_empty());
Some((first, second, third))
}
@ -20409,6 +20409,18 @@ mod tests {
assert_eq!(parsed.2.as_deref(), Some("Third"));
}
#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_extended_length_prefix() {
let mut bytes = Vec::new();
bytes.extend_from_slice(&[0x80, 0x03, b'A', b'B', b'C']);
bytes.extend_from_slice(&[0, 1, b'X']);
let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
.expect("triplet parser should decode extended-length prefix");
assert_eq!(parsed.0, "ABC");
assert_eq!(parsed.1, "X");
assert_eq!(parsed.2, None);
}
#[test]
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {

View file

@ -2937,9 +2937,12 @@ The low helper strip beneath that shared family is tighter now too: `0x0052ecd0`
cached bridge bands, opens `0x55f1`, parses three len-prefixed strings through `0x00531380`,
opens `0x55f2`, seeds the child through `0x00455b70`, dispatches slot `+0x48`, runs the local
follow-on `0x0052ebd0`, and then opens `0x55f3`. The widened save-side probe currently still
sees only two embedded `0x55f1` strings on grounded `q.gms`, so the remaining payload question is
whether that third parsed string is absent on ordinary saves, hidden behind different framing, or
only populated on a narrower infrastructure subset.
sees only two embedded `0x55f1` strings on grounded `q.gms`, but `0x00455b70` now makes that
result much less mysterious: it stores the three payload strings into `[this+0x206/+0x20a/+0x20e]`,
defaulting the second lane through a fixed literal when absent and defaulting the third lane back
to the first string when absent. So the remaining payload question is no longer “where is the
third string hiding?”; it is how the current dual-name save-side rows align with the full
payload-stream grouping and the later tagged value roles.
The child loader family is explicit now too: local `.rdata` at `0x005cfd00` proves the
`Infrastructure` child vtable uses the shared tagged callback strip directly, with
`+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining

View file

@ -69,9 +69,12 @@ Working rule:
disassembly now also shows the shared child payload callback `0x00455fc0` opening
`0x55f1 -> 0x55f2 -> 0x55f3`, parsing three `0x55f1` strings through `0x00531380`, seeding the
child through `0x00455b70`, and then dispatching slot `+0x48`; the widened save-side probe
currently sees `0` third `0x55f1` strings on grounded `q.gms`, so the next pass should ask
whether that third string is genuinely absent on ordinary saves or stored under different
framing than the current embedded-row scan.
currently sees `0` third `0x55f1` strings on grounded `q.gms`. That now looks less like a probe
failure and more like an ordinary fallback path, because direct disassembly of `0x00455b70`
stores the three payload strings into `[this+0x206/+0x20a/+0x20e]`, defaulting the second lane
through a fixed literal when absent and defaulting the third lane back to the first string when
absent. So the next pass should stay focused on payload-stream grouping and tagged value roles,
not on rediscovering a missing third-string encoding.
- The child loader identity is closed now too: local `.rdata` at `0x005cfd00` proves the
`Infrastructure` child vtable uses the shared tagged callback strip directly, with
`+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining