contracts: parse a schedule reply without slicing off a character boundary (ibx#258) - #364
Open
userFRM wants to merge 1 commit into
Open
contracts: parse a schedule reply without slicing off a character boundary (ibx#258)#364userFRM wants to merge 1 commit into
userFRM wants to merge 1 commit into
Conversation
6 tasks
…ndary The schedule parser validated byte positions and then sliced the `&str` at them. These are gateway strings decoded with `from_utf8_lossy`, so one invalid byte becomes a three-byte replacement character and every position after it shifts — a cut that was ASCII in the intended payload lands mid-character, and slicing a `&str` there is a panic. This runs on the hot loop, so it is an engine-down on malformed input rather than a dropped message. The format is `YYYYMMDD-HH:MM:SS`, ASCII by definition, and requiring that outright is what makes the byte arithmetic sound rather than incidentally correct: the guard establishes what is at bytes 8 and 11 and says nothing about 12 to 14, where a multi-byte character would panic the slice. The two date cuts ask for the range instead of assuming it. What replaces the panic is a degraded field, not a correct one — a reply this malformed has no recoverable date in it. The output is carried verbatim to the caller as `trading_hours`/`liquid_hours` and nothing in the tree parses it back, so a wrong string on already-corrupt input is the right trade against a dead engine. Closes deepentropy#258.
userFRM
force-pushed
the
fix/schedule-slice-panic
branch
from
July 30, 2026 16:44
186b237 to
84949c5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
trim_session_endpointvalidated byte positions and then sliced the string. The guard establishes what sits at bytes 8 and 11 and says nothing about 12 to 14 — and slicing a&stroff a character boundary is a panic, not an error. Two nearby date slices had the same shape, guarded on length alone.Reaching it takes one invalid byte in a trading-hours field. Frame bodies are decoded with
from_utf8_lossy, so that byte becomes a three-byte replacement character and every position after it shifts: a cut that was ASCII in the intended payload now lands mid-character.This runs on the hot loop, so it is an engine-down on malformed input rather than a dropped message.
The fix
The format is
YYYYMMDD-HH:MM:SS, ASCII by definition, and requiring that outright is what makes the byte arithmetic sound rather than incidentally correct. The two date slices ask for the range instead of assuming it, so a short or non-ASCII field yields a degraded date rather than a panic.The
is_asciiguard refuses nothing legitimate: the two fields it covers are populated only from the start- and end-time tags, which are timestamps. The timezone name — the one plausible non-ASCII carrier — is a separate field that never reaches this function. The guard only rejects strings that would previously have panicked, or that already returned unchanged.Degrading costs a wrong date field on one contract; a reply this malformed has no recoverable date in it. The output is carried verbatim to the caller as
trading_hours/liquid_hoursand nothing in the tree parses it back, so an ugly string on already-corrupt input is the right trade against a dead engine.Not reproduced against a live gateway: it needs the gateway to send a malformed schedule.
Closes #258.
Test plan
cargo test --offline --lib— 804 passed. The 2 failures areconfig::expiry_tests::{named_zone_converts_with_dst, instant_round_trips_to_wire}, which fail on the base commit too (fixed separately in config: resolve the legacy timezone names IB states its times in (ibx#335) #336).cargo check --offlineclean on every target:--lib,--features python,--bins,--examples, and each of the eighttests/*.rstargets individually.tests/ib_paper_compatcompared against a clean checkout of the base commit — line-identical sorted error sets.is_asciiguard, and reverting the date slices to a length check, each faila_schedule_that_is_not_ascii_does_not_panicby name — so both sites were genuinely reachable.a_well_formed_schedule_is_still_trimmedasserts the exact compact output, so the guard cannot pass by refusing everything.🤖 Generated with Claude Code