diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp index 6002ad9465..c997cfa59e 100644 --- a/media/libaudioclient/AudioTrackShared.cpp +++ b/media/libaudioclient/AudioTrackShared.cpp @@ -26,6 +26,24 @@ namespace android { +// TODO: consider pulling this into a shared header. +// safe_sub_overflow is used ensure that subtraction occurs in the same native type +// with proper 2's complement overflow. Without calling this function, it is possible, +// for example, that optimizing compilers may elect to treat 32 bit subtraction +// as 64 bit subtraction when storing into a 64 bit destination as integer overflow is +// technically undefined. +template, + std::decay_t>{}>> + // ensure arguments are same type (ignoring volatile, which is used in cblk variables). +auto safe_sub_overflow(const T& a, const U& b) { + std::decay_t result; + (void)__builtin_sub_overflow(a, b, &result); + // note if __builtin_sub_overflow returns true, an overflow occurred. + return result; +} + // used to clamp a value to size_t. TODO: move to another file. template size_t clampToSize(T x) { @@ -186,7 +204,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques front = cblk->u.mStreaming.mFront; } // write to rear, read from front - ssize_t filled = rear - front; + ssize_t filled = safe_sub_overflow(rear, front); // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { if (mIsOut) { @@ -684,7 +702,7 @@ void ServerProxy::flushBufferIfNeeded() const size_t overflowBit = mFrameCountP2 << 1; const size_t mask = overflowBit - 1; int32_t newFront = (front & ~mask) | (flush & mask); - ssize_t filled = rear - newFront; + ssize_t filled = safe_sub_overflow(rear, newFront); if (filled >= (ssize_t)overflowBit) { // front and rear offsets span the overflow bit of the p2 mask // so rebasing newFront on the front offset is off by the overflow bit. @@ -726,7 +744,7 @@ int32_t AudioTrackServerProxy::getRear() const const size_t overflowBit = mFrameCountP2 << 1; const size_t mask = overflowBit - 1; int32_t newRear = (rear & ~mask) | (stop & mask); - ssize_t filled = newRear - front; + ssize_t filled = safe_sub_overflow(newRear, front); // overflowBit is unsigned, so cast to signed for comparison. if (filled >= (ssize_t)overflowBit) { // front and rear offsets span the overflow bit of the p2 mask @@ -778,7 +796,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront); rear = cblk->u.mStreaming.mRear; } - ssize_t filled = rear - front; + ssize_t filled = safe_sub_overflow(rear, front); // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down", @@ -905,7 +923,7 @@ size_t AudioTrackServerProxy::framesReady() return mFrameCount; } const int32_t rear = getRear(); - ssize_t filled = rear - cblk->u.mStreaming.mFront; + ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront); // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down", @@ -931,7 +949,7 @@ size_t AudioTrackServerProxy::framesReadySafe() const return mFrameCount; } const int32_t rear = getRear(); - const ssize_t filled = rear - cblk->u.mStreaming.mFront; + const ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront); if (!(0 <= filled && (size_t) filled <= mFrameCount)) { return 0; // error condition, silently return 0. } @@ -1241,7 +1259,7 @@ size_t AudioRecordServerProxy::framesReadySafe() const } const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront); const int32_t rear = mCblk->u.mStreaming.mRear; - const ssize_t filled = rear - front; + const ssize_t filled = safe_sub_overflow(rear, front); if (!(0 <= filled && (size_t) filled <= mFrameCount)) { return 0; // error condition, silently return 0. }