Repository navigation
Keep a segment's time and position math from overflowing in a run of months - #96
Merged
Merged
Conversation
…months offset_us() and time_position() formed a sample count times 10^6 and a microsecond count times the rate in int64, which overflowed once one segment had run about 278 days at 384 kHz or 6 years at 48 kHz. Both now split the count at a multiple of the divisor (scaled_floor() and scaled_ceil() in sched/timeline.h), so only the remainder's product is formed. A resampled instance's start position and a drain's output count in GroupAudio had the same kind of product and use them too.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new helpers still have intermediate overflows for valid boundary inputs whose results fit int64.
1 open finding
What changed in this PR
Addresses #94 by reducing intermediate overflow in timeline and resampling calculations for long-running audio streams.
Changes:
- Adds scaled floor, ceiling, and rounding helpers.
- Applies them to timeline mappings and resampling start/drain calculations.
- Adds rounding and months-to-years regression cases.
| File | Description |
|---|---|
tests/test_sched_timeline.cpp |
Adds scaled-arithmetic and long-duration mapping tests. |
src/sched/timeline.h |
Defines the scaled division helpers. |
src/sched/timeline.cpp |
Uses helpers for position/time conversions. |
src/group_audio.cpp |
Uses helpers for resampling start and drain counts. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The bound covers scaled_round()'s numerator, and the doc no longer claims that only a result past int64 can overflow.
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.

Summary
Within one segment of an anchor,
offset_us()andtime_position()multiplied a sample count by 10^6 and a microsecond count by the rate in int64. Both overflowed (undefined behavior) once one segment had run about 278 days at 384 kHz, or about 6 years at 48 kHz, so a long-running live input would map positions and cells to wrong times.Change
scaled_floor(),scaled_ceil()andscaled_round()insched/timeline.h, next tofloor_div():n * mul / divwith n split at a multiple of div, so only the remainder's product (belowdiv * mul) is formed. Same results as before wherever the old products fit.offset_us()andtime_position()use them. This adds one 64-bit divide per call, per cell or frame, never per sample.GroupAudio, a resampled instance's start position ((first - origin) * in.rate, undefined after about 4 years at 192 kHz in, 384 kHz out) andfinish_drain()'s output count (span * 2 * out_rate, which wrapped in uint64 at the same point). Both run once per instance start or drain.segment_output_index()is unchanged: its picosecond term never exceeds a second, so splitting it would add a divide for nothing.Tests
SchedTimeline.TimeAndPositionYearsIntoOneSegment: one segment of 300 days at 384 kHz and 7 years at 48 and 44.1 kHz maps positions, times and cells as the Control rows at a second (and before p0) do. The 300-day row trips UBSan without the change.SchedTimeline.ScaledDivisionRounding: floor, ceil and half-up rounding of the helpers, negative inputs, and rows whose unsplit product passes 2^63.GroupAudiocall sites' overflow region is covered only through the helper table, since the pipeline harness cannot reach a segment years long; their wiring is pinned by the existingGroupAudiotests at ordinary durations.Closes #94