Refuse PyUmiPacket merge when the LEN field would overflow - #318
Open
eastagiletracker wants to merge 1 commit into
Open
Conversation
The merged LEN was written back into an eight-bit field without a range check, so merging packets whose combined length exceeds 256 words wrapped around: merging LEN=254 into LEN=5 produced LEN=4 and reported success, leaving a packet that claimed five words while holding 261 bytes. Refuse the merge instead, before the packet is resized, and add a test covering the boundary case, the overflow case and an ordinary merge.
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.
This PR proposes refusing a
PyUmiPacketmerge when the combined LEN would overflow the eight-bit LEN field, fixes #262. We include this PR work along with a full history of your repo at https://eastagiletracker.com/projects/400. You can sign in with your GitHub ID to claim ownership of the project.What goes wrong today
PyUmiPacket::mergewrites the merged length back withset_umi_len(&cmd, len + umi_len(other.cmd) + 1). LEN is an eight-bit field (DECL_UMI_SETTER(len, 8, 8)inswitchboard/cpp/umilib.h) andset_umi_bitsmasks the value to that width, so a merge whose combined length exceeds 256 words wraps around silently and still returnstrue. By that point the packet has already been resized and the incoming data copied in, so the caller is handed a transaction whose command describes far less data than the packet actually holds.Reproducing on
mainat 4287d19 —pip install .[test], then:Output on
main:That is the case @azaidy described in #262: (254 + 1) + (5 + 1) rolls back to a LEN of 4, and the merge reports success.
The change
mergenow returnsfalsewhenlen + umi_len(other.cmd) + 1would exceed the largest value LEN can represent, and it checks this beforeresize, so a refused merge leaves the packet untouched instead of half-modified. The limit is namedUMI_MAX_LENinswitchboard/cpp/umilib.h, beside the LEN accessors it belongs with.Nothing that could legitimately merge before stops merging: 256 words is the most a single UMI transaction can describe, so the only merges now refused are the ones that were producing incorrect packets.
umi_loopbackalready treats afalsereturn as "start a new transaction", and it applies the same rule on the TX and the RX side, so a stream that crosses the limit is split at the same point on both — I checked that a 512-word stream partitions identically either way.Verification
Same script, with the change applied:
examples/test_umi_packet_merge.pyadds three cases in the style ofexamples/test_bit_vector.py: the boundary merge that fills LEN exactly (LEN 254 plus LEN 0, giving LEN 255) still succeeds, the overflowing merge is refused and leaves the packet unchanged, and an ordinary short merge still concatenates its data as before. Run against an unpatched build, the middle case fails onassert not p.merge(q)while the other two pass, so the test is red without the change and green with it.I ran
pytestinexamples/before and after the change and got the same set of failures both times — the tentest_makecases, which need Verilator or Icarus and theumipackage, none of which I have locally — with the three new cases passing on top.makeintests/printsPASSwith the modified header, includingtorture.c, which compiles it as C rather than C++.flake8is clean.How this was managed
This work was tracked as Fix merging of PyUmiPacket on a board at https://eastagiletracker.com/projects/400 that was built from this repository's own issues and pull requests, 315 stories in all.
If you'd rather not receive contributions like this, reply
no-more-prson this pull request and we won't open any further ones on your repositories.Lawrence W. Sinclair
CEO / East Agile
linkedin.com/in/lwsinclair/
eastagile.com