1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-18 17:10:05 +02:00

Make many conversions sampleCount->size_t are explicit and checked...

... with run-time assertions.

I examined each place and reasoned that the narrowing was safe, and commented
why so.

Again, there are places where the sampleCount variable will later be changed
to have a different type, and they are not changed here.
This commit is contained in:
Paul Licameli 2016-08-31 00:49:22 -04:00
parent 78be459fa1
commit 078ff056e2
17 changed files with 220 additions and 77 deletions

View File

@ -74,6 +74,12 @@ public:
long long as_long_long() const { return value; } long long as_long_long() const { return value; }
size_t as_size_t() const {
wxASSERT(value >= 0);
wxASSERT(value <= std::numeric_limits<size_t>::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; } 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; }

View File

@ -592,7 +592,8 @@ struct AudioIO::ScrubQueue
auto remaining = pEntry->mDuration - pEntry->mPlayed; auto remaining = pEntry->mDuration - pEntry->mPlayed;
if (frames >= remaining) if (frames >= remaining)
{ {
frames -= remaining; // remaining is not more than frames
frames -= remaining.as_size_t();
pEntry->mPlayed = pEntry->mDuration; pEntry->mPlayed = pEntry->mDuration;
} }
else else

View File

@ -569,7 +569,8 @@ void FreqWindow::GetAudio()
mDataLen = 10485760; mDataLen = 10485760;
} }
else else
mDataLen = dataLen; // dataLen is not more than 10 * 2 ^ 20
mDataLen = dataLen.as_size_t();
mData = new float[mDataLen]; mData = new float[mDataLen];
track->Get((samplePtr)mData, floatSample, start, mDataLen); track->Get((samplePtr)mData, floatSample, start, mDataLen);
} }

View File

@ -633,7 +633,12 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
//delete[] rmsRight; //delete[] rmsRight;
auto startSample = (sampleCount)((mLeftTrack->GetRate() * t0) + 0.5); 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* meterFloatsArray = NULL;
float* tempFloatsArray = new float[nFrames]; float* tempFloatsArray = new float[nFrames];
bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray, floatSample, startSample, nFrames); bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray, floatSample, startSample, nFrames);

View File

@ -264,8 +264,12 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len,
theFile->GetMinMax(&block0Min, &block0Max, &block0RMS); theFile->GetMinMax(&block0Min, &block0Max, &block0RMS);
if (block0Min < min || block0Max > max) { if (block0Min < min || block0Max > max) {
auto s0 = start - theBlock.start; // start lies within theBlock:
const auto maxl0 = theBlock.start + theFile->GetLength() - start; 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 wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
const auto l0 = limitSampleBufferSize ( maxl0, len ); const auto l0 = limitSampleBufferSize ( maxl0, len );
@ -288,7 +292,8 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len,
if (block1Min < min || block1Max > max) { 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 wxASSERT(l0 <= mMaxSamples); // Vaughan, 2011-10-19
float partialMin, partialMax, partialRMS; float partialMin, partialMax, partialRMS;
@ -343,8 +348,11 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
{ {
const SeqBlock &theBlock = mBlock[block0]; const SeqBlock &theBlock = mBlock[block0];
const auto &theFile = theBlock.f; const auto &theFile = theBlock.f;
auto s0 = start - theBlock.start; // start lies within theBlock
const auto maxl0 = theBlock.start + theFile->GetLength() - start; 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 wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
const auto l0 = limitSampleBufferSize( maxl0, len ); const auto l0 = limitSampleBufferSize( maxl0, len );
@ -359,7 +367,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
const SeqBlock &theBlock = mBlock[block1]; const SeqBlock &theBlock = mBlock[block1];
const auto &theFile = theBlock.f; 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 wxASSERT(l0 <= mMaxSamples); // PRL: I think Vaughan missed this
float partialMin, partialMax, partialRMS; float partialMin, partialMax, partialRMS;
@ -405,7 +414,9 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &d
const SeqBlock &block0 = mBlock[b0]; const SeqBlock &block0 = mBlock[b0];
if (s0 != block0.start) { if (s0 != block0.start) {
const auto &file = block0.f; 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 wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29
Get(b0, buffer.ptr(), mSampleFormat, s0, blocklen); Get(b0, buffer.ptr(), mSampleFormat, s0, blocklen);
@ -422,7 +433,8 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &d
if (b1 > b0) { if (b1 > b0) {
const SeqBlock &block = mBlock[b1]; const SeqBlock &block = mBlock[b1];
const auto &file = block.f; 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 wxASSERT(file->IsAlias() || (blocklen <= mMaxSamples)); // Vaughan, 2012-02-29
if (blocklen < file->GetLength()) { if (blocklen < file->GetLength()) {
Get(b1, buffer.ptr(), mSampleFormat, block.start, blocklen); Get(b1, buffer.ptr(), mSampleFormat, block.start, blocklen);
@ -512,18 +524,24 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
// one block! // one block!
SeqBlock &block = *pBlock; 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); Read(buffer.ptr(), mSampleFormat, block, 0, splitPoint);
src->Get(0, buffer.ptr() + splitPoint*sampleSize, src->Get(0, buffer.ptr() + splitPoint*sampleSize,
mSampleFormat, 0, addedLen); mSampleFormat, 0, sAddedLen);
Read(buffer.ptr() + (splitPoint + addedLen)*sampleSize, Read(buffer.ptr() + (splitPoint + sAddedLen) * sampleSize,
mSampleFormat, block, mSampleFormat, block,
splitPoint, length - splitPoint); splitPoint, length - splitPoint);
auto file = 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; block.f = file;
@ -545,19 +563,22 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
SeqBlock &splitBlock = mBlock[b]; SeqBlock &splitBlock = mBlock[b];
auto splitLen = splitBlock.f->GetLength(); 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; unsigned int i;
if (srcNumBlocks <= 4) { 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); SampleBuffer sumBuffer(sum, mSampleFormat);
Read(sumBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint); Read(sumBuffer.ptr(), mSampleFormat, splitBlock, 0, splitPoint);
src->Get(0, sumBuffer.ptr() + splitPoint * sampleSize, src->Get(0, sumBuffer.ptr() + splitPoint * sampleSize,
mSampleFormat, mSampleFormat,
0, addedLen); 0, sAddedLen);
Read(sumBuffer.ptr() + (splitPoint + addedLen) * sampleSize, mSampleFormat, Read(sumBuffer.ptr() + (splitPoint + sAddedLen) * sampleSize, mSampleFormat,
splitBlock, splitPoint, splitBlock, splitPoint,
splitLen - splitPoint); splitLen - splitPoint);
@ -646,7 +667,10 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len)
sampleCount pos = 0; 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 {}; BlockFilePtr silentFile {};
if (len >= idealSamples) if (len >= idealSamples)
@ -659,7 +683,8 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len)
} }
if (len != 0) { if (len != 0) {
sTrack.mBlock.push_back(SeqBlock( sTrack.mBlock.push_back(SeqBlock(
make_blockfile<SilentBlockFile>(len), pos)); // len is not more than idealSamples:
make_blockfile<SilentBlockFile>( len.as_size_t() ), pos));
pos += len; pos += len;
} }
@ -770,7 +795,8 @@ sampleCount Sequence::GetBestBlockSize(sampleCount start) const
int numBlocks = mBlock.size(); int numBlocks = mBlock.size();
const SeqBlock &block = mBlock[b]; 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; decltype(result) length;
while(result < mMinSamples && b+1<numBlocks && while(result < mMinSamples && b+1<numBlocks &&
@ -943,7 +969,8 @@ void Sequence::HandleXMLEndTag(const wxChar *tag)
Internat::ToString((double)mMaxSamples, 0).c_str()); Internat::ToString((double)mMaxSamples, 0).c_str());
len = mMaxSamples; len = mMaxSamples;
} }
block.f = make_blockfile<SilentBlockFile>(len); // len is at most mMaxSamples:
block.f = make_blockfile<SilentBlockFile>( len.as_size_t() );
wxLogWarning( wxLogWarning(
wxT("Gap detected in project file. Replacing missing block file with silence.")); wxT("Gap detected in project file. Replacing missing block file with silence."));
mErrorOpening = true; mErrorOpening = true;
@ -1148,7 +1175,9 @@ bool Sequence::Get(int b, samplePtr buffer, sampleFormat format,
{ {
while (len) { while (len) {
const SeqBlock &block = mBlock[b]; 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); const auto blen = std::min(len, block.f->GetLength() - bstart);
Read(buffer, format, block, bstart, blen); Read(buffer, format, block, bstart, blen);
@ -1182,7 +1211,8 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format,
while (len != 0) { while (len != 0) {
SeqBlock &block = mBlock[b]; 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 fileLength = block.f->GetLength();
const auto blen = limitSampleBufferSize( fileLength - bstart, len ); 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; int blockStatus = b;
// How many samples or triples are needed? // How many samples or triples are needed?
const sampleCount startPosition =
std::max(sampleCount(0), (srcX - start) / divisor); const size_t startPosition =
const sampleCount inclusiveEndPosition = // srcX and start are in the same block
std::min((mMaxSamples / divisor) - 1, (nextSrcX - 1 - start) / divisor); 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; const auto num = 1 + inclusiveEndPosition - startPosition;
if (num <= 0) { if (num <= 0) {
// What? There was a zero length block file? // 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. // The previous pixel column might straddle blocks.
// If so, impute some of the data to it. // If so, impute some of the data to it.
if (b > block0 && pixel > 0) { 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); int diff(midPosition - filePosition);
if (diff > 0) { if (diff > 0) {
MinMaxSumsq values(temp, diff, divisor); MinMaxSumsq values(temp, diff, divisor);
@ -1423,7 +1458,9 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl,
decltype(filePosition) positionX = 0; decltype(filePosition) positionX = 0;
while (pixelX < nextPixel && while (pixelX < nextPixel &&
filePosition == 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; ++pixelX;
if (pixelX >= nextPixel) 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) { if (b0 == b1 && (length = (pBlock = &mBlock[b0])->f->GetLength()) - len >= mMinSamples) {
SeqBlock &b = *pBlock; SeqBlock &b = *pBlock;
sampleCount pos = start - b.start; // start is within block
sampleCount newLen = length - len; 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); scratch.Allocate(scratchSize, mSampleFormat);
Read(scratch.ptr(), mSampleFormat, b, 0, pos); Read(scratch.ptr(), mSampleFormat, b, 0, pos);
Read(scratch.ptr() + (pos * sampleSize), mSampleFormat, 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( b = SeqBlock(
mDirManager->NewSimpleBlockFile(scratch.ptr(), newLen, mSampleFormat), 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 // Otherwise combine it with the previous block (splitting them
// 50/50 if necessary). // 50/50 if necessary).
const SeqBlock &preBlock = mBlock[b0]; 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) {
if (preBufferLen >= mMinSamples || b0 == 0) { if (preBufferLen >= mMinSamples || b0 == 0) {
if (!scratch.ptr()) if (!scratch.ptr())
@ -1682,14 +1727,17 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
// the array, write it out. Otherwise combine it with the // the array, write it out. Otherwise combine it with the
// subsequent block (splitting them 50/50 if necessary). // subsequent block (splitting them 50/50 if necessary).
const SeqBlock &postBlock = mBlock[b1]; const SeqBlock &postBlock = mBlock[b1];
sampleCount postBufferLen = // start + len - 1 lies within postBlock
(postBlock.start + postBlock.f->GetLength()) - (start + len); const auto postBufferLen = (
(postBlock.start + postBlock.f->GetLength()) - (start + len)
).as_size_t();
if (postBufferLen) { if (postBufferLen) {
if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) { if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) {
if (!scratch.ptr()) if (!scratch.ptr())
// Last use of scratch, can ask for smaller // Last use of scratch, can ask for smaller
scratch.Allocate(postBufferLen, mSampleFormat); 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); Read(scratch.ptr(), mSampleFormat, postBlock, pos, postBufferLen);
auto file = auto file =
mDirManager->NewSimpleBlockFile(scratch.ptr(), postBufferLen, mSampleFormat); mDirManager->NewSimpleBlockFile(scratch.ptr(), postBufferLen, mSampleFormat);
@ -1703,7 +1751,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
if (!scratch.ptr()) if (!scratch.ptr())
// Last use of scratch, can ask for smaller // Last use of scratch, can ask for smaller
scratch.Allocate(sum, mSampleFormat); 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(), mSampleFormat, postBlock, pos, postBufferLen);
Read(scratch.ptr() + (postBufferLen * sampleSize), mSampleFormat, Read(scratch.ptr() + (postBufferLen * sampleSize), mSampleFormat,
postpostBlock, 0, postpostLen); postpostBlock, 0, postpostLen);

View File

@ -1319,7 +1319,11 @@ void TrackArtist::DrawIndividualSamples(wxDC &dc, int leftOffset, const wxRect &
const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset; const double t1 = zoomInfo.PositionToTime(rect.width - 1, -leftOffset) - toffset;
const auto s1 = sampleCount(ceil(t1 * rate)); 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) if (slen <= 0)
return; return;

View File

@ -4575,7 +4575,9 @@ void TrackPanel::HandleSampleEditingDrag( wxMouseEvent & event )
//Go from the smaller to larger sample. //Go from the smaller to larger sample.
const auto start = std::min( s0, mDrawingLastDragSample); const auto start = std::min( s0, mDrawingLastDragSample);
const auto end = std::max( 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) { if (size == 1) {
mDrawingTrack->Set((samplePtr)&newLevel, floatSample, start, size); mDrawingTrack->Set((samplePtr)&newLevel, floatSample, start, size);
} }
@ -4583,7 +4585,8 @@ void TrackPanel::HandleSampleEditingDrag( wxMouseEvent & event )
std::vector<float> values(size); std::vector<float> values(size);
for (auto i = start; i <= end; ++i) { for (auto i = start; i <= end; ++i) {
//This interpolates each sample linearly: //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) * mDrawingLastDragSampleValue + (newLevel - mDrawingLastDragSampleValue) *
(i - mDrawingLastDragSample).as_float() / (i - mDrawingLastDragSample).as_float() /
(s0 - mDrawingLastDragSample).as_float(); (s0 - mDrawingLastDragSample).as_float();

View File

@ -645,13 +645,16 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
if (right > left) { if (right > left) {
float *b; 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) if (seqFormat == floatSample)
b = &((float *)mAppendBuffer.ptr())[left]; b = &((float *)mAppendBuffer.ptr())[sLeft];
else { else {
b = new float[len]; b = new float[len];
CopySamples(mAppendBuffer.ptr() + left*SAMPLE_SIZE(seqFormat), CopySamples(mAppendBuffer.ptr() + sLeft * SAMPLE_SIZE(seqFormat),
seqFormat, seqFormat,
(samplePtr)b, floatSample, len); (samplePtr)b, floatSample, len);
} }
@ -831,7 +834,8 @@ bool SpecCache::CalculateOneSpectrum
if (start + myLen > numSamples) { if (start + myLen > numSamples) {
// Near the end of the clip, pad right with zeroes as needed. // 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) for (decltype(myLen) ii = newlen; ii < myLen; ++ii)
adj[ii] = 0; adj[ii] = 0;
myLen = newlen; myLen = newlen;

View File

@ -2042,11 +2042,24 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
{ {
inclipDelta = -startDelta; // make positive value inclipDelta = -startDelta; // make positive value
samplesToCopy -= inclipDelta; samplesToCopy -= inclipDelta;
// samplesToCopy is now either len or
// (clipEnd - clipStart) - (start - clipStart)
// == clipEnd - start > 0
// samplesToCopy is not more than len
//
startDelta = 0; 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)), if (!clip->GetSamples(
format, inclipDelta, samplesToCopy)) (samplePtr)(((char*)buffer) +
startDelta.as_size_t() *
SAMPLE_SIZE(format)),
format, inclipDelta, samplesToCopy.as_size_t() ))
{ {
wxASSERT(false); // should always work wxASSERT(false); // should always work
return false; return false;
@ -2078,11 +2091,24 @@ bool WaveTrack::Set(samplePtr buffer, sampleFormat format,
{ {
inclipDelta = -startDelta; // make positive value inclipDelta = -startDelta; // make positive value
samplesToCopy -= inclipDelta; samplesToCopy -= inclipDelta;
// samplesToCopy is now either len or
// (clipEnd - clipStart) - (start - clipStart)
// == clipEnd - start > 0
// samplesToCopy is not more than len
//
startDelta = 0; 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)), if (!clip->SetSamples(
format, inclipDelta, samplesToCopy)) (samplePtr)(((char*)buffer) +
startDelta.as_size_t() *
SAMPLE_SIZE(format)),
format, inclipDelta, samplesToCopy.as_size_t() ))
{ {
wxASSERT(false); // should always work wxASSERT(false); // should always work
return false; return false;
@ -2128,10 +2154,13 @@ void WaveTrack::GetEnvelopeValues(double *buffer, size_t bufferLen,
if (rt0 < dClipStartTime) 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); auto nDiff = (sampleCount)floor((dClipStartTime - rt0) * mRate + 0.5);
rbuf += nDiff; auto snDiff = nDiff.as_size_t();
wxASSERT(nDiff <= rlen); rbuf += snDiff;
rlen -= nDiff; wxASSERT(snDiff <= rlen);
rlen -= snDiff;
rt0 = dClipStartTime; rt0 = dClipStartTime;
} }
@ -2722,30 +2751,45 @@ constSamplePtr WaveTrackCache::Get(sampleFormat format,
if (initLen > 0) { if (initLen > 0) {
// This might be fetching zeroes between clips // This might be fetching zeroes between clips
mOverlapBuffer.Resize(len, format); 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; return 0;
remaining -= initLen; wxASSERT( sinitLen <= remaining );
remaining -= sinitLen;
start += initLen; start += initLen;
buffer = mOverlapBuffer.ptr() + initLen * SAMPLE_SIZE(format); buffer = mOverlapBuffer.ptr() + sinitLen * SAMPLE_SIZE(format);
} }
// Now satisfy the request from the buffers // Now satisfy the request from the buffers
for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) { for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) {
const auto starti = start - mBuffers[ii].start; 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 = const auto leni =
std::min( sampleCount( remaining ), mBuffers[ii].len - starti ); std::min( sampleCount( remaining ), mBuffers[ii].len - starti );
if (initLen <= 0 && leni == len) { if (initLen <= 0 && leni == len) {
// All is contiguous already. We can completely avoid copying // 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) { 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) { if (buffer == 0) {
mOverlapBuffer.Resize(len, format); mOverlapBuffer.Resize(len, format);
buffer = mOverlapBuffer.ptr(); buffer = mOverlapBuffer.ptr();
} }
const size_t size = sizeof(float) * leni; // leni is positive and not more than remaining
memcpy(buffer, mBuffers[ii].data + starti, size); const size_t size = sizeof(float) * leni.as_size_t();
remaining -= leni; // 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; start += leni;
buffer += size; buffer += size;
} }

View File

@ -312,7 +312,9 @@ bool EffectAutoDuck::Process()
for (auto i = pos; i < pos + len; i++) for (auto i = pos; i < pos + len; i++)
{ {
rmsSum -= rmsWindow[rmsPos]; 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]; rmsSum += rmsWindow[rmsPos];
rmsPos = (rmsPos + 1) % kRMSWindowSize; rmsPos = (rmsPos + 1) % kRMSWindowSize;
@ -551,7 +553,8 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
if (gain < mDuckAmountDb) if (gain < mDuckAmountDb)
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); t->Set((samplePtr)buf, floatSample, pos, len);

View File

@ -487,6 +487,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
float * inBuffer = new float[inBufferSize]; float * inBuffer = new float[inBufferSize];
// mFactor is at most 100-fold so this shouldn't overflow size_t
auto outBufferSize = auto outBufferSize =
(sampleCount)((mFactor * inBufferSize) + 10); (sampleCount)((mFactor * inBufferSize) + 10);
float * outBuffer = new float[outBufferSize]; float * outBuffer = new float[outBufferSize];

View File

@ -86,10 +86,15 @@ bool EffectEcho::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames
} }
histPos = 0; histPos = 0;
histLen = (sampleCount) (mSampleRate * delay); auto requestedHistLen = (sampleCount) (mSampleRate * delay);
// Guard against extreme delay values input by the user // Guard against extreme delay values input by the user
try { try {
// Guard against huge delay values from the user.
// Don't violate the assertion in as_size_t
if (requestedHistLen !=
(histLen = static_cast<size_t>(requestedHistLen.as_long_long())))
throw std::bad_alloc{};
history = new float[histLen]; history = new float[histLen];
} }
catch ( const std::bad_alloc& ) { catch ( const std::bad_alloc& ) {

View File

@ -1610,7 +1610,8 @@ bool Effect::ProcessTrack(int count,
if (curBlockSize > inputRemaining) if (curBlockSize > inputRemaining)
{ {
// We've reached the last block...set current block size to what's left // 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; inputRemaining = 0;
// Clear the remainder of the buffers so that a full block can be passed // 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. // so overlay them by shifting the remaining output samples.
else if (curDelay > 0) 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++) 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; curDelay = 0;
} }

View File

@ -103,7 +103,8 @@ bool EffectRepair::Process()
const auto s0 = track->TimeToLongSamples(t0); const auto s0 = track->TimeToLongSamples(t0);
const auto s1 = track->TimeToLongSamples(t1); 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; const auto len = s1 - s0;
if (s0 == repair0 && s1 == repair1) { if (s0 == repair0 && s1 == repair1) {
@ -113,8 +114,12 @@ bool EffectRepair::Process()
break; break;
} }
if (!ProcessOne(count, track, if (!ProcessOne(count, track, s0,
s0, len, repairStart, repairLen)) { // len is at most 5 * 128.
len.as_size_t(),
repairStart,
// repairLen is at most 128.
repairLen.as_size_t() )) {
bGoodResult = false; bGoodResult = false;
break; break;
} }

View File

@ -495,7 +495,8 @@ bool EffectTruncSilence::DoRemoval
// Make sure the cross-fade does not affect non-silent frames // Make sure the cross-fade does not affect non-silent frames
if (wt->LongSamplesToTime(blendFrames) > inLength) 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 // Perform cross-fade in memory

View File

@ -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, CopySamples(mCurBuffer[ch].ptr() + offset*SAMPLE_SIZE(floatSample), floatSample,
(samplePtr)buffer, floatSample, (samplePtr)buffer, floatSample,
len); len);

View File

@ -393,8 +393,9 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
// find the number of samples for the leading silence // find the number of samples for the leading silence
// UNSAFE_SAMPLE_COUNT_TRUNCATION // UNSAFE_SAMPLE_COUNT_TRUNCATION
// -- but used only experimentally as of this writing // -- but used only experimentally as of this writing
// Is there a proof size_t will not overflow? // Is there a proof size_t will not overflow size_t?
auto amt = actualDecodeStart - start; // Result is surely nonnegative.
auto amt = (actualDecodeStart - start).as_size_t();
auto cache = make_movable<FFMpegDecodeCache>(); auto cache = make_movable<FFMpegDecodeCache>();
//printf("skipping/zeroing %i samples. - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",amt,actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len); //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 nChannels = mDecodeCache[i]->numChannels;
auto samplesHit = ( 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) 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. //find the start of the hit relative to the cache buffer start.
// UNSAFE_SAMPLE_COUNT_TRUNCATION // UNSAFE_SAMPLE_COUNT_TRUNCATION
// -- but used only experimentally as of this writing // -- but used only experimentally as of this writing
// Is there a proof size_t will not overflow? // 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. //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 const auto hitStartInRequest = start < mDecodeCache[i]->start
? len - samplesHit : sampleCount{ 0 }; ? len - samplesHit : sampleCount{ 0 };