Fix unsigned underflow in AudioEntry.audioDataLengthBytes() - #140
Merged
dimitris-c merged 2 commits intoSep 30, 2026
Merged
dimitris-c merged 2 commits into
dimitris-c merged 2 commits into
Conversation
A live stream can report a length smaller than the parsed header offset. UInt(source.length) - UInt(dataOffset) then underflows and Swift traps (SIGTRAP), reached through duration() once packets have arrived. Return 0 in that case, which is what duration() already returns for a stream of unknown length. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The timer source repeats every 100 ms. On a slow CI runner with --parallel it can fire a second time before wait(for:) returns, and the second fulfill() raises an API violation that fails the suite. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thank you for this fix, looks good |
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.
Problem
AudioEntry.audioDataLengthBytes()subtracts the parsed data offset from the source length asUInt:When
dataOffset > source.length, the subtraction underflows and Swift traps (SIGTRAP). This happens on live streams whose reported length is smaller than the header offset the file-stream parser found.duration()reaches it throughcalculatedBitrate(), which becomes non-zero as soon as packets have been processed, so the crash hits during normal playback, not at the edges.For context: in a radio app built on AudioStreaming,
AudioEntry.duration()→audioDataLengthBytes()was the top fatal crash on iOS, 45 installs in a month across four app versions.Fix
Compare before subtracting, and return
0whendataOffset >= length.duration()already returns0for a stream of unknown length, so callers see the same value they get for any live stream. The explicitdataByteCountpath is unchanged.Tests
AudioEntryTests, a new file with five tests that use a fixed-lengthCoreAudioStreamSourcestub:dataOffset > length→0. Against the currentmainthis test does not fail, it takes the test runner down:xctest … exited with unexpected signal code 5.dataOffset == length→0.length - dataOffset.dataByteCountstill wins.duration()is0when the offset exceeds the length, with a bitrate set.With the fix, the full suite passes:
swift test→Executed 59 tests, with 0 failures.Notes
The PR also carries one small, separate test-only commit. The first CI run failed in
DispatchTimerSourceTests.test_HandlerIsExecuted_On_The_Specified_Queue, which this change does not touch:API violation - multiple calls made to -[XCTestExpectation fulfill]. The timer repeats every 100 ms, and on a slow runner with--parallelit can fire again beforewaitreturns. The test now setsassertForOverFulfill = false. Happy to drop that commit if you prefer it separately.The change is confined to
AudioEntry.audioDataLengthBytes(); there are no public API changes. Our next app release, now in App Review, carries this fix from our fork. Thanks for merging #138 and releasing it in 1.4.5 — this is the last patch we carry on top of upstream.