Skip to content

rtpklv: do not reuse buffer of returned KLV units - #1154

Merged
aler9 merged 1 commit into
bluenviron:mainfrom
winklemad:fix/klv-buffer-reuse
Sep 5, 2026
Merged

aler9 merged 1 commit into
bluenviron:mainfrom
winklemad:fix/klv-buffer-reuse

Conversation

@winklemad

Copy link
Copy Markdown
Contributor

Decode() returns a slice that points into the decoder's internal buffer, and the next call to Decode() overwrites that same array in place (reset() truncates it to zero length, then the next unit is appended into it).

A caller that still holds the previous unit therefore ends up reading the bytes of the next one, or a torn mix of the two when the sizes differ. In mediamtx the decoded unit is handed to readers through a ring buffer and consumed on a different goroutine (recorder, HLS, MPEG-TS, WebRTC), so this is also a data race.

rtpklv is the only decoder under pkg/format that returns its own reusable state. The others either build a fresh slice in joinFragments() or clear the buffer, with the comment "do not reuse frameBuffer to avoid race conditions" in rtph264, rtph265, rtpav1, rtpvp8 and rtpmpeg1video.

The fix clears the buffer instead of truncating it, so every unit gets its own array. It costs one allocation per KLV unit, the same tradeoff the other decoders already make. Tests cover a following unit of the same size and a shorter one.

Decode() returns a slice that points to the decoder's internal buffer, and
the next call to Decode() overwrites that same array in place. A caller
that holds the previous unit - for instance while it is being recorded or
forwarded on another goroutine - ends up reading the bytes of the next
unit, or a torn mix of both when the sizes differ.

Clear the buffer instead of truncating it, so each unit gets its own
array. This is what the h264, h265, av1, vp8 and mpeg1video decoders
already do, at the cost of one allocation per unit.
@aler9

aler9 commented Sep 5, 2026

Copy link
Copy Markdown
Member

verified and merged, thanks!

@aler9
aler9 enabled auto-merge (squash) September 5, 2026 06:53
@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.15%. Comparing base (3e20947) to head (9da2a0c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1154      +/-   ##
==========================================
- Coverage   87.17%   87.15%   -0.02%     
==========================================
  Files         133      133              
  Lines       10587    10587              
==========================================
- Hits         9229     9227       -2     
- Misses       1358     1360       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aler9
aler9 merged commit ad4c486 into bluenviron:main Sep 5, 2026
7 of 18 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