diff --git a/include/audacity/Types.h b/include/audacity/Types.h index f00dbf0ac..67f6b4d3a 100644 --- a/include/audacity/Types.h +++ b/include/audacity/Types.h @@ -74,6 +74,12 @@ public: long long as_long_long() const { return value; } + size_t as_size_t() const { + wxASSERT(value >= 0); + wxASSERT(value <= std::numeric_limits::max()); + return value; + } + sampleCount &operator += (sampleCount b) { value += b.value; return *this; } sampleCount &operator -= (sampleCount b) { value -= b.value; return *this; } sampleCount &operator *= (sampleCount b) { value *= b.value; return *this; } diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index cf826d31f..d3b6c732d 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -592,7 +592,8 @@ struct AudioIO::ScrubQueue auto remaining = pEntry->mDuration - pEntry->mPlayed; if (frames >= remaining) { - frames -= remaining; + // remaining is not more than frames + frames -= remaining.as_size_t(); pEntry->mPlayed = pEntry->mDuration; } else diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp index 7cb792d6c..ccb377235 100644 --- a/src/FreqWindow.cpp +++ b/src/FreqWindow.cpp @@ -569,7 +569,8 @@ void FreqWindow::GetAudio() mDataLen = 10485760; } else - mDataLen = dataLen; + // dataLen is not more than 10 * 2 ^ 20 + mDataLen = dataLen.as_size_t(); mData = new float[mDataLen]; track->Get((samplePtr)mData, floatSample, start, mDataLen); } diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 601fe0756..e2d68601a 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -633,7 +633,12 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1) //delete[] rmsRight; auto startSample = (sampleCount)((mLeftTrack->GetRate() * t0) + 0.5); - auto nFrames = (sampleCount)((mLeftTrack->GetRate() * (t1 - t0)) + 0.5); + auto scnFrames = (sampleCount)((mLeftTrack->GetRate() * (t1 - t0)) + 0.5); + + // Expect that the difference of t1 and t0 is the part of a track played + // in about 1/20 second (ticks of TrackPanel timer), so this won't overflow + auto nFrames = scnFrames.as_size_t(); + float* meterFloatsArray = NULL; float* tempFloatsArray = new float[nFrames]; bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray, floatSample, startSample, nFrames); diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 18d53b8b0..5d01e9a69 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -264,8 +264,12 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len, theFile->GetMinMax(&block0Min, &block0Max, &block0RMS); if (block0Min < min || block0Max > max) { - auto s0 = start - theBlock.start; - const auto maxl0 = theBlock.start + theFile->GetLength() - start; + // start lies within theBlock: + auto s0 = ( start - theBlock.start ).as_size_t(); + const auto maxl0 = ( + // start lies within theBlock: + theBlock.start + theFile->GetLength() - start + ).as_size_t(); wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19 const auto l0 = limitSampleBufferSize ( maxl0, len ); @@ -288,7 +292,8 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len, if (block1Min < min || block1Max > max) { - const auto l0 = (start + len) - theBlock.start; + // start + len - 1 lies in theBlock: + const auto l0 = ( start + len - theBlock.start ).as_size_t(); wxASSERT(l0 <= mMaxSamples); // Vaughan, 2011-10-19 float partialMin, partialMax, partialRMS; @@ -343,8 +348,11 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, { const SeqBlock &theBlock = mBlock[block0]; const auto &theFile = theBlock.f; - auto s0 = start - theBlock.start; - const auto maxl0 = theBlock.start + theFile->GetLength() - start; + // start lies within theBlock + auto s0 = ( start - theBlock.start ).as_size_t(); + // start lies within theBlock + const auto maxl0 = + (theBlock.start + theFile->GetLength() - start).as_size_t(); wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19 const auto l0 = limitSampleBufferSize( maxl0, len ); @@ -359,7 +367,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len, const SeqBlock &theBlock = mBlock[block1]; const auto &theFile = theBlock.f; - const auto l0 = (start + len) - theBlock.start; + // start + len - 1 lies within theBlock + const auto l0 = ( start + len - theBlock.start ).as_size_t(); wxASSERT(l0 <= mMaxSamples); // PRL: I think Vaughan missed this float partialMin, partialMax, partialRMS; @@ -405,7 +414,9 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr &d const SeqBlock &block0 = mBlock[b0]; if (s0 != block0.start) { const auto &file = block0.f; - blocklen = std::min(s1, block0.start + file->GetLength()) - s0; + // Nonnegative result is length of block0 or less: + blocklen = + ( std::min(s1, block0.start + file->GetLength()) - s0 ).as_size_t(); wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29 Get(b0, buffer.ptr(), mSampleFormat, s0, blocklen); @@ -422,7 +433,8 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr &d if (b1 > b0) { const SeqBlock &block = mBlock[b1]; const auto &file = block.f; - blocklen = (s1 - block.start); + // s1 is within block: + blocklen = (s1 - block.start).as_size_t(); wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29 if (blocklen < file->GetLength()) { Get(b1, buffer.ptr(), mSampleFormat, block.start, blocklen); @@ -512,18 +524,24 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) // one block! SeqBlock &block = *pBlock; - SampleBuffer buffer(largerBlockLen, mSampleFormat); + // largerBlockLen is not more than mMaxSamples... + SampleBuffer buffer(largerBlockLen.as_size_t(), mSampleFormat); - int splitPoint = s - block.start; + // ...and addedLen is not more than largerBlockLen + auto sAddedLen = addedLen.as_size_t(); + // s lies within block: + auto splitPoint = ( s - block.start ).as_size_t(); Read(buffer.ptr(), mSampleFormat, block, 0, splitPoint); src->Get(0, buffer.ptr() + splitPoint*sampleSize, - mSampleFormat, 0, addedLen); - Read(buffer.ptr() + (splitPoint + addedLen)*sampleSize, + mSampleFormat, 0, sAddedLen); + Read(buffer.ptr() + (splitPoint + sAddedLen) * sampleSize, mSampleFormat, block, splitPoint, length - splitPoint); auto file = - mDirManager->NewSimpleBlockFile(buffer.ptr(), largerBlockLen, mSampleFormat); + mDirManager->NewSimpleBlockFile( + // largerBlockLen is not more than mMaxSamples... + buffer.ptr(), largerBlockLen.as_size_t(), mSampleFormat); block.f = file; @@ -545,19 +563,22 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) SeqBlock &splitBlock = mBlock[b]; auto splitLen = splitBlock.f->GetLength(); - int splitPoint = s - splitBlock.start; + // s lies within splitBlock + auto splitPoint = ( s - splitBlock.start ).as_size_t(); unsigned int i; if (srcNumBlocks <= 4) { - sampleCount sum = splitLen + addedLen; + // addedLen is at most four times maximum block size + auto sAddedLen = addedLen.as_size_t(); + const auto sum = splitLen + sAddedLen; SampleBuffer sumBuffer(sum, mSampleFormat); Read(sumBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint); src->Get(0, sumBuffer.ptr() + splitPoint * sampleSize, mSampleFormat, - 0, addedLen); - Read(sumBuffer.ptr() + (splitPoint + addedLen) * sampleSize, mSampleFormat, + 0, sAddedLen); + Read(sumBuffer.ptr() + (splitPoint + sAddedLen) * sampleSize, mSampleFormat, splitBlock, splitPoint, splitLen - splitPoint); @@ -646,7 +667,10 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len) sampleCount pos = 0; - sTrack.mBlock.reserve((len + idealSamples - 1) / idealSamples); + // Could nBlocks overflow a size_t? Not very likely. You need perhaps + // 2 ^ 52 samples which is over 3000 years at 44.1 kHz. + auto nBlocks = (len + idealSamples - 1) / idealSamples; + sTrack.mBlock.reserve(nBlocks.as_size_t()); BlockFilePtr silentFile {}; if (len >= idealSamples) @@ -659,7 +683,8 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len) } if (len != 0) { sTrack.mBlock.push_back(SeqBlock( - make_blockfile(len), pos)); + // len is not more than idealSamples: + make_blockfile( len.as_size_t() ), pos)); pos += len; } @@ -770,7 +795,8 @@ sampleCount Sequence::GetBestBlockSize(sampleCount start) const int numBlocks = mBlock.size(); const SeqBlock &block = mBlock[b]; - sampleCount result = (block.start + block.f->GetLength() - start); + // start is in block: + auto result = (block.start + block.f->GetLength() - start).as_size_t(); decltype(result) length; while(result < mMinSamples && b+1(len); + // len is at most mMaxSamples: + block.f = make_blockfile( len.as_size_t() ); wxLogWarning( wxT("Gap detected in project file. Replacing missing block file with silence.")); mErrorOpening = true; @@ -1148,7 +1175,9 @@ bool Sequence::Get(int b, samplePtr buffer, sampleFormat format, { while (len) { const SeqBlock &block = mBlock[b]; - const sampleCount bstart = (start - (block.start)); + // start is in block + const auto bstart = (start - block.start).as_size_t(); + // bstart is not more than block length const auto blen = std::min(len, block.f->GetLength() - bstart); Read(buffer, format, block, bstart, blen); @@ -1182,7 +1211,8 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format, while (len != 0) { SeqBlock &block = mBlock[b]; - const sampleCount bstart = start - block.start; + // start is within block + const auto bstart = ( start - block.start ).as_size_t(); const auto fileLength = block.f->GetLength(); const auto blen = limitSampleBufferSize( fileLength - bstart, len ); @@ -1343,10 +1373,14 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, int blockStatus = b; // How many samples or triples are needed? - const sampleCount startPosition = - std::max(sampleCount(0), (srcX - start) / divisor); - const sampleCount inclusiveEndPosition = - std::min((mMaxSamples / divisor) - 1, (nextSrcX - 1 - start) / divisor); + + const size_t startPosition = + // srcX and start are in the same block + std::max(sampleCount(0), (srcX - start) / divisor).as_size_t(); + const size_t inclusiveEndPosition = + // nextSrcX - 1 and start are in the same block + std::min((sampleCount(mMaxSamples) / divisor) - 1, + (nextSrcX - 1 - start) / divisor).as_size_t(); const auto num = 1 + inclusiveEndPosition - startPosition; if (num <= 0) { // What? There was a zero length block file? @@ -1392,7 +1426,8 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, // The previous pixel column might straddle blocks. // If so, impute some of the data to it. if (b > block0 && pixel > 0) { - sampleCount midPosition = (whereNow - start) / divisor; + // whereNow and start are in the same block + auto midPosition = ((whereNow - start) / divisor).as_size_t(); int diff(midPosition - filePosition); if (diff > 0) { MinMaxSumsq values(temp, diff, divisor); @@ -1423,7 +1458,9 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, decltype(filePosition) positionX = 0; while (pixelX < nextPixel && filePosition == - (positionX = (std::min(s1 - 1, where[pixelX]) - start) / divisor) + (positionX = ( + // s1 - 1 or where[pixelX] and start are in the same block + (std::min(s1 - 1, where[pixelX]) - start) / divisor).as_size_t() ) ) ++pixelX; if (pixelX >= nextPixel) @@ -1608,14 +1645,21 @@ bool Sequence::Delete(sampleCount start, sampleCount len) if (b0 == b1 && (length = (pBlock = &mBlock[b0])->f->GetLength()) - len >= mMinSamples) { SeqBlock &b = *pBlock; - sampleCount pos = start - b.start; - sampleCount newLen = length - len; + // start is within block + auto pos = ( start - b.start ).as_size_t(); + wxASSERT(len < length); + // len must be less than length + // because start + len - 1 is also in the block... + auto newLen = ( length - len ).as_size_t(); scratch.Allocate(scratchSize, mSampleFormat); Read(scratch.ptr(), mSampleFormat, b, 0, pos); Read(scratch.ptr() + (pos * sampleSize), mSampleFormat, - b, pos + len, newLen - pos); + b, + // ... and therefore pos + len + // is not more than the length of the block + ( pos + len ).as_size_t(), newLen - pos); b = SeqBlock( mDirManager->NewSimpleBlockFile(scratch.ptr(), newLen, mSampleFormat), @@ -1645,7 +1689,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len) // Otherwise combine it with the previous block (splitting them // 50/50 if necessary). const SeqBlock &preBlock = mBlock[b0]; - sampleCount preBufferLen = start - preBlock.start; + // start is within preBlock + auto preBufferLen = ( start - preBlock.start ).as_size_t(); if (preBufferLen) { if (preBufferLen >= mMinSamples || b0 == 0) { if (!scratch.ptr()) @@ -1682,14 +1727,17 @@ bool Sequence::Delete(sampleCount start, sampleCount len) // the array, write it out. Otherwise combine it with the // subsequent block (splitting them 50/50 if necessary). const SeqBlock &postBlock = mBlock[b1]; - sampleCount postBufferLen = - (postBlock.start + postBlock.f->GetLength()) - (start + len); + // start + len - 1 lies within postBlock + const auto postBufferLen = ( + (postBlock.start + postBlock.f->GetLength()) - (start + len) + ).as_size_t(); if (postBufferLen) { if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) { if (!scratch.ptr()) // Last use of scratch, can ask for smaller scratch.Allocate(postBufferLen, mSampleFormat); - sampleCount pos = (start + len) - postBlock.start; + // start + len - 1 lies within postBlock + auto pos = (start + len - postBlock.start).as_size_t(); Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen); auto file = mDirManager->NewSimpleBlockFile(scratch.ptr(), postBufferLen, mSampleFormat); @@ -1703,7 +1751,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len) if (!scratch.ptr()) // Last use of scratch, can ask for smaller scratch.Allocate(sum, mSampleFormat); - sampleCount pos = (start + len) - postBlock.start; + // start + len - 1 lies within postBlock + auto pos = (start + len - postBlock.start).as_size_t(); Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen); Read(scratch.ptr() + (postBufferLen * sampleSize), mSampleFormat, postpostBlock, 0, postpostLen); diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 994ec1c76..043270687 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -1319,7 +1319,11 @@ void TrackArtist::DrawIndividualSamples(wxDC &dc, int leftOffset, const wxRect & const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset; const auto s1 = sampleCount(ceil(t1 * rate)); - sampleCount slen = std::min(snSamples - s0, s1 - s0 + 1); + + // Assume size_t will not overflow, else we wouldn't be here drawing the + // few individual samples + auto slen = std::min(snSamples - s0, s1 - s0 + 1).as_size_t(); + if (slen <= 0) return; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index fd710232f..592fb1a5f 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -4575,7 +4575,9 @@ void TrackPanel::HandleSampleEditingDrag( wxMouseEvent & event ) //Go from the smaller to larger sample. const auto start = std::min( s0, mDrawingLastDragSample); const auto end = std::max( s0, mDrawingLastDragSample); - const int size = end - start + 1; + // Few enough samples to be drawn individually on screen will not + // overflow size_t: + const auto size = ( end - start + 1 ).as_size_t(); if (size == 1) { mDrawingTrack->Set((samplePtr)&newLevel, floatSample, start, size); } @@ -4583,7 +4585,8 @@ void TrackPanel::HandleSampleEditingDrag( wxMouseEvent & event ) std::vector values(size); for (auto i = start; i <= end; ++i) { //This interpolates each sample linearly: - values[i - start] = + // i - start will not overflow size_t either: + values[( i - start ).as_size_t()] = mDrawingLastDragSampleValue + (newLevel - mDrawingLastDragSampleValue) * (i - mDrawingLastDragSample).as_float() / (s0 - mDrawingLastDragSample).as_float(); diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index b13f3ea81..d98c85246 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -645,13 +645,16 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, if (right > left) { float *b; - sampleCount len = right-left; + // left is nonnegative and at most mAppendBufferLen: + auto sLeft = left.as_size_t(); + // The difference is at most mAppendBufferLen: + size_t len = ( right - left ).as_size_t(); if (seqFormat == floatSample) - b = &((float *)mAppendBuffer.ptr())[left]; + b = &((float *)mAppendBuffer.ptr())[sLeft]; else { b = new float[len]; - CopySamples(mAppendBuffer.ptr() + left*SAMPLE_SIZE(seqFormat), + CopySamples(mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat), seqFormat, (samplePtr)b, floatSample, len); } @@ -831,7 +834,8 @@ bool SpecCache::CalculateOneSpectrum if (start + myLen > numSamples) { // Near the end of the clip, pad right with zeroes as needed. - int newlen = numSamples - start; + // newlen is bounded by myLen: + auto newlen = ( numSamples - start ).as_size_t(); for (decltype(myLen) ii = newlen; ii < myLen; ++ii) adj[ii] = 0; myLen = newlen; diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 56ee8d2d5..556d1840a 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -2042,11 +2042,24 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format, { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; + // samplesToCopy is now either len or + // (clipEnd - clipStart) - (start - clipStart) + // == clipEnd - start > 0 + // samplesToCopy is not more than len + // startDelta = 0; + // startDelta is zero + } + else { + // startDelta is nonnegative and less than than len + // samplesToCopy is positive and not more than len } - if (!clip->GetSamples((samplePtr)(((char*)buffer)+startDelta*SAMPLE_SIZE(format)), - format, inclipDelta, samplesToCopy)) + if (!clip->GetSamples( + (samplePtr)(((char*)buffer) + + startDelta.as_size_t() * + SAMPLE_SIZE(format)), + format, inclipDelta, samplesToCopy.as_size_t() )) { wxASSERT(false); // should always work return false; @@ -2078,11 +2091,24 @@ bool WaveTrack::Set(samplePtr buffer, sampleFormat format, { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; + // samplesToCopy is now either len or + // (clipEnd - clipStart) - (start - clipStart) + // == clipEnd - start > 0 + // samplesToCopy is not more than len + // startDelta = 0; + // startDelta is zero + } + else { + // startDelta is nonnegative and less than than len + // samplesToCopy is positive and not more than len } - if (!clip->SetSamples((samplePtr)(((char*)buffer)+startDelta*SAMPLE_SIZE(format)), - format, inclipDelta, samplesToCopy)) + if (!clip->SetSamples( + (samplePtr)(((char*)buffer) + + startDelta.as_size_t() * + SAMPLE_SIZE(format)), + format, inclipDelta, samplesToCopy.as_size_t() )) { wxASSERT(false); // should always work return false; @@ -2128,10 +2154,13 @@ void WaveTrack::GetEnvelopeValues(double *buffer, size_t bufferLen, if (rt0 < dClipStartTime) { + // This is not more than the number of samples in + // (endTime - startTime) which is bufferLen: auto nDiff = (sampleCount)floor((dClipStartTime - rt0) * mRate + 0.5); - rbuf += nDiff; - wxASSERT(nDiff <= rlen); - rlen -= nDiff; + auto snDiff = nDiff.as_size_t(); + rbuf += snDiff; + wxASSERT(snDiff <= rlen); + rlen -= snDiff; rt0 = dClipStartTime; } @@ -2722,30 +2751,45 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format, if (initLen > 0) { // This might be fetching zeroes between clips mOverlapBuffer.Resize(len, format); - if (!mPTrack->Get(mOverlapBuffer.ptr(), format, start, initLen)) + // initLen is not more than len: + auto sinitLen = initLen.as_size_t(); + if (!mPTrack->Get(mOverlapBuffer.ptr(), format, start, sinitLen)) return 0; - remaining -= initLen; + wxASSERT( sinitLen <= remaining ); + remaining -= sinitLen; start += initLen; - buffer = mOverlapBuffer.ptr() + initLen * SAMPLE_SIZE(format); + buffer = mOverlapBuffer.ptr() + sinitLen * SAMPLE_SIZE(format); } // Now satisfy the request from the buffers for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) { const auto starti = start - mBuffers[ii].start; + // Treatment of initLen above establishes this loop invariant, + // and statements below preserve it: + wxASSERT(starti >= 0); + + // This may be negative const auto leni = std::min( sampleCount( remaining ), mBuffers[ii].len - starti ); if (initLen <= 0 && leni == len) { // All is contiguous already. We can completely avoid copying - return samplePtr(mBuffers[ii].data + starti); + // leni is nonnegative, therefore start falls within mBuffers[ii], + // so starti is bounded between 0 and buffer length + return samplePtr(mBuffers[ii].data + starti.as_size_t() ); } else if (leni > 0) { + // leni is nonnegative, therefore start falls within mBuffers[ii] + // But we can't satisfy all from one buffer, so copy if (buffer == 0) { mOverlapBuffer.Resize(len, format); buffer = mOverlapBuffer.ptr(); } - const size_t size = sizeof(float) * leni; - memcpy(buffer, mBuffers[ii].data + starti, size); - remaining -= leni; + // leni is positive and not more than remaining + const size_t size = sizeof(float) * leni.as_size_t(); + // starti is less than mBuffers[ii].len and nonnegative + memcpy(buffer, mBuffers[ii].data + starti.as_size_t(), size); + wxASSERT( leni <= remaining ); + remaining -= leni.as_size_t(); start += leni; buffer += size; } diff --git a/src/effects/AutoDuck.cpp b/src/effects/AutoDuck.cpp index b7f730b56..1e0c1b6b4 100644 --- a/src/effects/AutoDuck.cpp +++ b/src/effects/AutoDuck.cpp @@ -312,7 +312,9 @@ bool EffectAutoDuck::Process() for (auto i = pos; i < pos + len; i++) { rmsSum -= rmsWindow[rmsPos]; - rmsWindow[rmsPos] = buf[i - pos] * buf[i - pos]; + // i - pos is bounded by len: + auto index = ( i - pos ).as_size_t(); + rmsWindow[rmsPos] = buf[ index ] * buf[ index ]; rmsSum += rmsWindow[rmsPos]; rmsPos = (rmsPos + 1) % kRMSWindowSize; @@ -551,7 +553,8 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t, if (gain < mDuckAmountDb) gain = mDuckAmountDb; - buf[i - pos] *= DB_TO_LINEAR(gain); + // i - pos is bounded by len: + buf[ ( i - pos ).as_size_t() ] *= DB_TO_LINEAR(gain); } t->Set((samplePtr)buf, floatSample, pos, len); diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index f280dfe7a..54a50f143 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -487,6 +487,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track, float * inBuffer = new float[inBufferSize]; + // mFactor is at most 100-fold so this shouldn't overflow size_t auto outBufferSize = (sampleCount)((mFactor * inBufferSize) + 10); float * outBuffer = new float[outBufferSize]; diff --git a/src/effects/Echo.cpp b/src/effects/Echo.cpp index bbfbdd930..4993b7bc3 100644 --- a/src/effects/Echo.cpp +++ b/src/effects/Echo.cpp @@ -86,10 +86,15 @@ bool EffectEcho::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames } histPos = 0; - histLen = (sampleCount) (mSampleRate * delay); + auto requestedHistLen = (sampleCount) (mSampleRate * delay); // Guard against extreme delay values input by the user try { + // Guard against huge delay values from the user. + // Don't violate the assertion in as_size_t + if (requestedHistLen != + (histLen = static_cast(requestedHistLen.as_long_long()))) + throw std::bad_alloc{}; history = new float[histLen]; } catch ( const std::bad_alloc& ) { diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 5f05a0c8b..50191a945 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1610,7 +1610,8 @@ bool Effect::ProcessTrack(int count, if (curBlockSize > inputRemaining) { // We've reached the last block...set current block size to what's left - curBlockSize = inputRemaining; + // inputRemaining is positive and bounded by a size_t + curBlockSize = inputRemaining.as_size_t(); inputRemaining = 0; // Clear the remainder of the buffers so that a full block can be passed @@ -1709,10 +1710,12 @@ bool Effect::ProcessTrack(int count, // so overlay them by shifting the remaining output samples. else if (curDelay > 0) { - curBlockSize -= curDelay; + // curDelay is bounded by curBlockSize: + auto delay = curDelay.as_size_t(); + curBlockSize -= delay; for (int i = 0; i < chans; i++) { - memmove(mOutBufPos[i], mOutBufPos[i] + curDelay, sizeof(float) * curBlockSize); + memmove(mOutBufPos[i], mOutBufPos[i] + delay, sizeof(float) * curBlockSize); } curDelay = 0; } diff --git a/src/effects/Repair.cpp b/src/effects/Repair.cpp index 1cf54f63a..400008f1e 100644 --- a/src/effects/Repair.cpp +++ b/src/effects/Repair.cpp @@ -103,7 +103,8 @@ bool EffectRepair::Process() const auto s0 = track->TimeToLongSamples(t0); const auto s1 = track->TimeToLongSamples(t1); - const auto repairStart = (repair0 - s0); + // The difference is at most 2 * 128: + const auto repairStart = (repair0 - s0).as_size_t(); const auto len = s1 - s0; if (s0 == repair0 && s1 == repair1) { @@ -113,8 +114,12 @@ bool EffectRepair::Process() break; } - if (!ProcessOne(count, track, - s0, len, repairStart, repairLen)) { + if (!ProcessOne(count, track, s0, + // len is at most 5 * 128. + len.as_size_t(), + repairStart, + // repairLen is at most 128. + repairLen.as_size_t() )) { bGoodResult = false; break; } diff --git a/src/effects/TruncSilence.cpp b/src/effects/TruncSilence.cpp index fc670330a..2bc1494e8 100644 --- a/src/effects/TruncSilence.cpp +++ b/src/effects/TruncSilence.cpp @@ -495,7 +495,8 @@ bool EffectTruncSilence::DoRemoval // Make sure the cross-fade does not affect non-silent frames if (wt->LongSamplesToTime(blendFrames) > inLength) { - blendFrames = wt->TimeToLongSamples(inLength); + // Result is not more than blendFrames: + blendFrames = wt->TimeToLongSamples(inLength).as_size_t(); } // Perform cross-fade in memory diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index fb8942b55..4c197c2ae 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -1752,7 +1752,9 @@ int NyquistEffect::GetCallback(float *buffer, int ch, } } - long offset = (mCurStart[ch] + start) - mCurBufferStart[ch]; + // We have guaranteed above that this is nonnegative and bounded by + // mCurBufferLen[ch]: + auto offset = ( mCurStart[ch] + start - mCurBufferStart[ch] ).as_size_t(); CopySamples(mCurBuffer[ch].ptr() + offset*SAMPLE_SIZE(floatSample), floatSample, (samplePtr)buffer, floatSample, len); diff --git a/src/ondemand/ODDecodeFFmpegTask.cpp b/src/ondemand/ODDecodeFFmpegTask.cpp index f80ecd721..8f2d4b77a 100644 --- a/src/ondemand/ODDecodeFFmpegTask.cpp +++ b/src/ondemand/ODDecodeFFmpegTask.cpp @@ -393,8 +393,9 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo // find the number of samples for the leading silence // UNSAFE_SAMPLE_COUNT_TRUNCATION // -- but used only experimentally as of this writing - // Is there a proof size_t will not overflow? - auto amt = actualDecodeStart - start; + // Is there a proof size_t will not overflow size_t? + // Result is surely nonnegative. + auto amt = (actualDecodeStart - start).as_size_t(); auto cache = make_movable(); //printf("skipping/zeroing %i samples. - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",amt,actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len); @@ -513,14 +514,19 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat, auto nChannels = mDecodeCache[i]->numChannels; auto samplesHit = ( + // Proof that the result is never negative: consider four cases + // of FFMIN and FFMAX choices, and use the if-condition enclosing. + // The result is not more than len. FFMIN(start+len,mDecodeCache[i]->start+mDecodeCache[i]->len) - - FFMAX(mDecodeCache[i]->start,start) - ); + - FFMAX(mDecodeCache[i]->start, start) + ).as_size_t(); //find the start of the hit relative to the cache buffer start. // UNSAFE_SAMPLE_COUNT_TRUNCATION // -- but used only experimentally as of this writing // Is there a proof size_t will not overflow? - const auto hitStartInCache = FFMAX(sampleCount{0},start-mDecodeCache[i]->start); + const auto hitStartInCache = + // result is less than mDecodeCache[i]->len: + FFMAX(sampleCount{0},start-mDecodeCache[i]->start).as_size_t(); //we also need to find out which end was hit - if it is the tail only we need to update from a later index. const auto hitStartInRequest = start < mDecodeCache[i]->start ? len - samplesHit : sampleCount{ 0 };