Skip to content

fix: refuse a base container left concrete beside its own children - #4

Merged
mysma-9403 merged 2 commits into
mainfrom
fix/a-concrete-base-matches-everything
Oct 11, 2026
Merged

mysma-9403 merged 2 commits into
mainfrom
fix/a-concrete-base-matches-everything

Conversation

@mysma-9403

Copy link
Copy Markdown
Contributor

abstract defaults to false in XTCE, so a base SequenceContainer that nobody marked —
the ordinary CCSDS primary-header shape, which is most definitions — is emitted as a concrete
container. Its generated matches is true for any buffer long enough to hold it, and the
module-level decode counts how many containers match:

if FlightPacket::matches(data) { matched += 1; … }   // body is `true`
if StatusReport::matches(data) { matched += 1; … }
if matched > 1 { return Err(DecodeError::Ambiguous) }

So every packet matched the base and its own child, and decode answered Ambiguous for
all of them. A generated decoder that rejects every packet, from a definition that generated
without a word of complaint — and the place you would find out is the spacecraft.

Refused at generation time now, naming the container and giving both ways out:

$ xtce-flight generate concrete_base.xml -o out.rs
error: cannot compile <SequenceContainer> in FlightPacket: this container has no restriction
criteria, so it matches every packet long enough to hold it; beside the other containers
generated here that makes every packet ambiguous. Mark it abstract="true" if other containers
inherit from it, or give it criteria that select it

Narrow on purpose: only when there is more than one container. A lone concrete container with
no criteria is the whole definition and decodes fine, so it still generates.

Reproduced against the bundled definition by removing one attribute from it; flight_shapes.xml
itself still generates its two structs. 43 tests, fmt and clippy clean.

`abstract` defaults to false in XTCE, so a base SequenceContainer that nobody
marked — the ordinary CCSDS primary-header shape — is emitted as a concrete
container. Its generated `matches` is `true` for any buffer long enough to hold
it, and the module-level `decode` counts how many containers match. So every
packet matched the base and its own child, and `decode` answered `Ambiguous`
for all of them: a generated decoder that rejects every packet, from a
definition that generated without a word.

Refused at generation time now, naming the container and saying both ways out:

    error: cannot compile <SequenceContainer> in FlightPacket: this container
    has no restriction criteria, so it matches every packet long enough to hold
    it; beside the other containers generated here that makes every packet
    ambiguous. Mark it abstract="true" if other containers inherit from it, or
    give it criteria that select it

Only when there is more than one container: a lone concrete container with no
criteria is the whole definition and decodes fine.

Found by a review sweep and reproduced with the bundled definition, by removing
one attribute from it. 43 tests, fmt and clippy clean.
`if a && let Some(b) = c` is unstable there, and a toolchain of 1.99 compiles
it without a word. Checked against `cargo +1.85` this time rather than against
the one that happens to be installed.
@mysma-9403
mysma-9403 merged commit b9ddc98 into main Oct 11, 2026
4 checks passed
@mysma-9403
mysma-9403 deleted the fix/a-concrete-base-matches-everything branch October 11, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant