From aa29325be3769e1d11e3674ab2ce234c3a120add Mon Sep 17 00:00:00 2001 From: dimitris-c Date: Mon, 8 Dec 2025 14:00:05 +0200 Subject: [PATCH] Adds band-aid for possible arithmetic overflow --- .../AudioPlayerRenderProcessor.swift | 44 +++++++++++++++++-- .../Streaming/Helpers/BufferContext.swift | 8 +++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift index 08e2a27..23f8ee4 100644 --- a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift +++ b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift @@ -65,6 +65,12 @@ final class AudioPlayerRenderProcessor: NSObject { let frameSizeInBytes = bufferContext.sizeInBytes let used = bufferContext.frameUsedCount let start = bufferContext.frameStartIndex + #if DEBUG + assert(start < bufferContext.totalFrameCount, + "frameStartIndex (\(start)) >= totalFrameCount (\(bufferContext.totalFrameCount)) - logic error!") + assert(used <= bufferContext.totalFrameCount, + "frameUsedCount (\(used)) > totalFrameCount (\(bufferContext.totalFrameCount)) - logic error!") + #endif let end = (bufferContext.frameStartIndex + bufferContext.frameUsedCount) % bufferContext.totalFrameCount let signal = rendererContext.waiting.value && used < bufferContext.totalFrameCount / 2 @@ -122,12 +128,33 @@ final class AudioPlayerRenderProcessor: NSObject { totalFramesCopied = framesToCopy rendererContext.lock.lock() + #if DEBUG + if totalFramesCopied > bufferContext.frameUsedCount { + Logger.debug("Buffer race: tried to consume %d frames but only %d available (reset likely occurred)", + category: .audioRendering, + args: totalFramesCopied, bufferContext.frameUsedCount) + } + #endif bufferContext.frameStartIndex = (bufferContext.frameStartIndex + totalFramesCopied) % bufferContext.totalFrameCount - bufferContext.frameUsedCount -= totalFramesCopied + if totalFramesCopied <= bufferContext.frameUsedCount { + bufferContext.frameUsedCount -= totalFramesCopied + } else { + bufferContext.frameUsedCount = 0 + } rendererContext.lock.unlock() } else { - let frameToCopy = min(inNumberFrames, bufferContext.totalFrameCount - start) + let frameToCopy: UInt32 + if start < bufferContext.totalFrameCount { + frameToCopy = min(inNumberFrames, bufferContext.totalFrameCount - start) + } else { + #if DEBUG + Logger.debug("Buffer race: start index %d >= totalFrameCount %d (reset likely occurred)", + category: .audioRendering, + args: start, bufferContext.totalFrameCount) + #endif + frameToCopy = 0 + } bufferList.mBuffers.mNumberChannels = 2 bufferList.mBuffers.mDataByteSize = frameSizeInBytes * frameToCopy @@ -160,8 +187,19 @@ final class AudioPlayerRenderProcessor: NSObject { totalFramesCopied = frameToCopy + moreFramesToCopy rendererContext.lock.lock() + #if DEBUG + if totalFramesCopied > bufferContext.frameUsedCount { + Logger.debug("Buffer race: tried to consume %d frames but only %d available (reset likely occurred)", + category: .audioRendering, + args: totalFramesCopied, bufferContext.frameUsedCount) + } + #endif bufferContext.frameStartIndex = (bufferContext.frameStartIndex + totalFramesCopied) % bufferContext.totalFrameCount - bufferContext.frameUsedCount -= totalFramesCopied + if totalFramesCopied <= bufferContext.frameUsedCount { + bufferContext.frameUsedCount -= totalFramesCopied + } else { + bufferContext.frameUsedCount = 0 + } rendererContext.lock.unlock() } diff --git a/AudioStreaming/Streaming/Helpers/BufferContext.swift b/AudioStreaming/Streaming/Helpers/BufferContext.swift index ca39222..ef89d1d 100644 --- a/AudioStreaming/Streaming/Helpers/BufferContext.swift +++ b/AudioStreaming/Streaming/Helpers/BufferContext.swift @@ -13,7 +13,13 @@ final class BufferContext { var frameUsedCount: UInt32 = 0 var end: UInt32 { - (frameStartIndex + frameUsedCount) % totalFrameCount + #if DEBUG + assert(frameStartIndex < totalFrameCount, + "frameStartIndex (\(frameStartIndex)) exceeds totalFrameCount (\(totalFrameCount)) - logic error!") + assert(frameUsedCount <= totalFrameCount, + "frameUsedCount (\(frameUsedCount)) exceeds totalFrameCount (\(totalFrameCount)) - logic error!") + #endif + return (frameStartIndex + frameUsedCount) % totalFrameCount } init(sizeInBytes: UInt32, totalFrameCount: UInt32) {