From 83e5427fe0a0db02ba7a4df332bea0c2a941bf11 Mon Sep 17 00:00:00 2001 From: manuaudio Date: Sat, 15 Aug 2026 09:00:38 -0700 Subject: [PATCH] Opus: do not convert out of range properties to int Opus is the one worth reading twice: its granule clock is fixed at 48 kHz, so unlike the other formats no absurd declared sample rate is needed. A 64 bit granule position alone is enough. At 2^62 samples the millisecond length is ~9.6e16 and the conversion to int is undefined: taglib/ogg/opus/opusproperties.cpp:156:39: runtime error: 9.60768e+16 is outside the range of representable values of type 'int' The bitrate on the next line has the same shape as the other formats, but because the divisor cannot be made arbitrarily small at a fixed 48 kHz it needs a stream of several megabytes to overflow, so I have not built a test file for it. It is guarded for consistency rather than on demonstrated evidence. Leave the field at its default rather than converting. One report before the change, none after. The 23 FLAC, APE, Ogg Vorbis, Opus and Speex files in tests/data report identical channels, sample rate, bitrate and length before and after, and the suite runs 576 tests either way. Assisted-By: Claude Code (Claude Opus 5) --- taglib/ogg/opus/opusproperties.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/taglib/ogg/opus/opusproperties.cpp b/taglib/ogg/opus/opusproperties.cpp index d7561b90..eb626ff7 100644 --- a/taglib/ogg/opus/opusproperties.cpp +++ b/taglib/ogg/opus/opusproperties.cpp @@ -29,6 +29,8 @@ #include "opusproperties.h" +#include + #include "tstring.h" #include "tdebug.h" #include "oggpageheader.h" @@ -153,8 +155,18 @@ void Opus::Properties::read(File *file) for (unsigned int i = 0; i < 2; ++i) { fileLengthWithoutOverhead -= file->packet(i).size(); } - d->length = static_cast(length + 0.5); - d->bitrate = static_cast(static_cast(fileLengthWithoutOverhead) * 8.0 / length + 0.5); + // The granule positions are 64 bit, so even at the fixed 48 kHz clock + // the millisecond length can land outside int, and a short stream does + // the same to the bitrate. Converting a double the destination type + // cannot represent is undefined, so leave the field at its default + // instead. + if(length > 0.0 && length < static_cast(std::numeric_limits::max())) { + d->length = static_cast(length + 0.5); + + const double bitrate = static_cast(fileLengthWithoutOverhead) * 8.0 / length; + if(bitrate >= 0.0 && bitrate < static_cast(std::numeric_limits::max())) + d->bitrate = static_cast(bitrate + 0.5); + } } } else {