Skip to content

fix(key): Document text lifetime and guard matchText against torn slices#325

Merged
rockorager merged 1 commit into
rockorager:mainfrom
omkarbhad:fix/match-text-torn-slice
Apr 29, 2026
Merged

fix(key): Document text lifetime and guard matchText against torn slices#325
rockorager merged 1 commit into
rockorager:mainfrom
omkarbhad:fix/match-text-torn-slice

Conversation

@omkarbhad
Copy link
Copy Markdown
Contributor

Summary

Key.text, when populated, is a slice into the parser's per-event scratch buffer. The buffer is reused on the next decode, so a Key that outlives one parser turn — for example, an event queued to a worker thread or held across a Loop turn — ends up pointing at the next event's bytes. matchText then compares against arbitrary memory and either returns wrong matches or dereferences a torn slice header into freed memory.

Change

Two pieces, both in src/Key.zig:

  1. Doc the lifetime contract. The doc comment on matchText (and by implication Key.text) now states explicitly that text is parser-scoped and callers retaining a Key must copy. This is the actual fix — the bug is a usage contract that wasn't written down.

  2. Defensive bounds inside matchText. A single keystroke produces at most 4 UTF-8 bytes. Anything longer is unambiguously a corrupted slice header, so we bail rather than read. Also pulls the optional unwrap out of the chain so the body isn't sprinkled with self.text.?.

No API change, no platform impact, no new dependencies.

Test plan

  • zig build clean against current main (post-Zig 0.16 port #316).
  • zig build test green.
  • Reviewer confirms the doc-comment phrasing matches how they want callers to think about Key lifetime.

Notes

Found while debugging a downstream consumer that drains events on a different thread than the input parser runs on. The lifetime invariant is real and worth documenting regardless of whether the bounds guard lands; happy to drop the guard if you'd rather force callers to honour the doc-comment.

Closes — none directly. Adjacent to the general "events crossing thread boundaries" surface.

Copy link
Copy Markdown
Owner

@rockorager rockorager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with the documentation change, but not the change to limit the text field to max 4 bytes, that is incorrect for how the key is used.

Comment thread src/Key.zig Outdated
@omkarbhad omkarbhad force-pushed the fix/match-text-torn-slice branch from 0c7edf3 to f5a9537 Compare April 29, 2026 13:44
@omkarbhad
Copy link
Copy Markdown
Contributor Author

You're right — paste and IME break the 4-byte assumption. Dropped the cap, kept the doc-only path. The downstream that hit this fixes its side by reading key.codepoint and never dereferencing key.text after the parser turn — exactly the contract the comment now spells out.

@rockorager rockorager merged commit 0c9d3cb into rockorager:main Apr 29, 2026
4 checks passed
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.

2 participants