DSF: do not convert an out of range length to unsigned int

DSF::Properties::read computes

    d->length = d->samplingFrequency > 0
        ? static_cast<unsigned int>(static_cast<double>(d->sampleCount)
                                    * 1000.0 / d->samplingFrequency + 0.5)
        : 0;

sampleCount is a long long taken straight from the file and
samplingFrequency is an unsigned int from the file, so the millisecond
count can land well outside unsigned int. Converting a floating point
value the destination type cannot represent is undefined:

  taglib/dsf/dsfproperties.cpp:132:35: runtime error: 8.41595e+09 is
  outside the range of representable values of type 'unsigned int'
    #0 TagLib::DSF::Properties::read(TagLib::ByteVector const&)
    #1 TagLib::DSF::Properties::Properties(...)
    #10 TagLib::FileRef::FileRef(char const*, bool, ...)

A negative sampleCount converts just as badly, so guard that too.

Report an unknown length instead of converting, matching what a zero
sampling frequency already does. Nothing changes for a valid file:
tests/data/empty10ms.dsf reads lengthMs=10 bitrate=5645 rate=2822400
ch=2 both before and after.

Found by mutating the files in tests/data and running them through a
parse, read properties and save round trip under UBSan.

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 3b6da94771
commit b136be8c3c
+14 -3
View File
@@ -26,6 +26,8 @@
#include "dsfproperties.h"
#include <limits>
using namespace TagLib;
class DSF::Properties::PropertiesPrivate
@@ -128,7 +130,16 @@ void DSF::Properties::read(const ByteVector &data)
d->bitrate = static_cast<unsigned int>(
d->samplingFrequency * d->bitsPerSample * d->channelNum / 1000.0 + 0.5);
d->length = d->samplingFrequency > 0
? static_cast<unsigned int>(static_cast<double>(d->sampleCount) * 1000.0 / d->samplingFrequency + 0.5)
: 0;
// sampleCount and samplingFrequency both come straight from the file, so the
// millisecond count can land outside unsigned int, and converting a double that
// does not fit the destination type is undefined. Report an unknown length rather
// than converting, which is what a zero sampling frequency already does.
d->length = 0;
if(d->samplingFrequency > 0 && d->sampleCount > 0) {
const double milliseconds =
static_cast<double>(d->sampleCount) * 1000.0 / d->samplingFrequency + 0.5;
if(milliseconds < static_cast<double>(std::numeric_limits<unsigned int>::max()))
d->length = static_cast<unsigned int>(milliseconds);
}
}