DSDIFF: do not convert an out of range length to int

Same shape as the DSF change: sampleCount comes from a chunk size in the
file and sampleRate is read from it, so

    static_cast<int>(static_cast<double>(d->sampleCount) * 1000.0
                     / d->sampleRate + 0.5)

can be handed a value int cannot represent, which is undefined.

In the PR I said I had not demonstrated this one, because chunkFits
bounds the sample count by the file length so a few mutated bytes will
not do it. Constructing the file it does need - a 700 kB DSD chunk with
a sample rate of 1 - reaches it:

  taglib/dsdiff/dsdiffproperties.cpp:61:24: runtime error: 2.8e+09 is
  outside the range of representable values of type 'int'

Two reports before the change, none after. tests/data/empty10ms.dff is
unchanged at lengthMs=10 bitrate=5644 rate=2822400 ch=2.

Assisted-By: Claude Code (Claude Opus 5)
This commit is contained in:
manuaudio
2026-08-15 17:52:56 +02:00
committed by Urs Fleisch
parent b136be8c3c
commit c275891a77
+13 -3
View File
@@ -25,6 +25,8 @@
#include "dsdiffproperties.h"
#include <limits>
#include "tstring.h"
using namespace TagLib;
@@ -57,9 +59,17 @@ DSDIFF::Properties::Properties(unsigned int sampleRate,
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>(static_cast<double>(d->sampleCount) * 1000.0 / d->sampleRate + 0.5)
: 0;
// sampleCount is derived from a chunk size in the file and sampleRate is read from
// it, so the millisecond count can land outside int, and converting a double the
// destination type cannot represent is undefined. Report an unknown length instead,
// which is what a zero sample rate already does.
d->length = 0;
if(d->sampleRate > 0 && d->sampleCount > 0) {
const double milliseconds =
static_cast<double>(d->sampleCount) * 1000.0 / d->sampleRate + 0.5;
if(milliseconds < static_cast<double>(std::numeric_limits<int>::max()))
d->length = static_cast<int>(milliseconds);
}
}
DSDIFF::Properties::~Properties() = default;