diff options
| author | Daniil Cherednik <[email protected]> | 2026-06-26 23:32:56 +0200 |
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2026-06-27 10:11:47 +0200 |
| commit | 75b3d391652e8cb61a98685fcfc5185891007429 (patch) | |
| tree | ffd320927df61382d18edf650069cf3db2bbe7cd | |
| parent | e9434fe78a4bb68199409e523990d31322e48c7b (diff) | |
The decoder now skips an invalid frame and emits silence.
| -rw-r--r-- | src/atrac/at1/atrac1.cpp | 11 | ||||
| -rw-r--r-- | src/atrac1denc.cpp | 20 | ||||
| -rw-r--r-- | src/lib/bitstream/bitstream.cpp | 11 |
3 files changed, 36 insertions, 6 deletions
diff --git a/src/atrac/at1/atrac1.cpp b/src/atrac/at1/atrac1.cpp index b361ad5..fd11c66 100644 --- a/src/atrac/at1/atrac1.cpp +++ b/src/atrac/at1/atrac1.cpp @@ -19,6 +19,8 @@ #include "atrac1.h" #include "bitstream/bitstream.h" +#include <stdexcept> + namespace NAtracDEnc { namespace NAtrac1 { @@ -38,6 +40,15 @@ std::array<int, 3> TAtrac1Data::TBlockSizeMod::Parse(NBitStream::TBitStream* str tmp[1] = 2 - stream->Read(2); tmp[2] = 3 - stream->Read(2); stream->Read(2); //skip unused 2 bits + + // LogCount is used as the shift count for the number of MDCT blocks + // (1 << LogCount). A malformed frame can encode a value that makes this + // negative, which is undefined behaviour and leads to out-of-bounds + // access during the (I)MDCT. Reject such frames. + for (int i = 0; i < 3; i++) { + if (tmp[i] < 0) + throw std::runtime_error("invalid ATRAC1 block size mode"); + } return tmp; } diff --git a/src/atrac1denc.cpp b/src/atrac1denc.cpp index 5c362fd..b30b72f 100644 --- a/src/atrac1denc.cpp +++ b/src/atrac1denc.cpp @@ -145,11 +145,21 @@ TPCMEngine::TProcessLambda TAtrac1Decoder::GetLambda() { TBitStream bitstream(frame->Get(), frame->Size()); - TAtrac1Data::TBlockSizeMod mode(&bitstream); - TAtrac1Dequantiser dequantiser; - vector<float> specs; - specs.resize(512);; - dequantiser.Dequant(&bitstream, mode, &specs[0]); + vector<float> specs(512, 0.0f); + TAtrac1Data::TBlockSizeMod mode; + + try { + mode = TAtrac1Data::TBlockSizeMod(&bitstream); + TAtrac1Dequantiser dequantiser; + dequantiser.Dequant(&bitstream, mode, &specs[0]); + } catch (const std::exception& e) { + // Malformed frame: decode it as a silent frame (zero spectrum, + // neutral block size) so the per-channel overlap/QMF state stays + // consistent for the frames that follow. + std::cerr << "Skipping invalid ATRAC1 frame: " << e.what() << std::endl; + specs.assign(512, 0.0f); + mode = TAtrac1Data::TBlockSizeMod(); + } IMdct(&specs[0], mode, &PcmBufLow[channel][0], &PcmBufMid[channel][0], &PcmBufHi[channel][0]); SynthesisFilterBank[channel].Synthesis(&sum[0], &PcmBufLow[channel][0], &PcmBufMid[channel][0], &PcmBufHi[channel][0]); diff --git a/src/lib/bitstream/bitstream.cpp b/src/lib/bitstream/bitstream.cpp index ddff907..f731c0a 100644 --- a/src/lib/bitstream/bitstream.cpp +++ b/src/lib/bitstream/bitstream.cpp @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <cstdint> +#include <stdexcept> #include "bitstream.h" #ifndef BIGENDIAN_ORDER @@ -67,8 +68,16 @@ uint32_t TBitStream::Read(int n) { const int bytesPos = ReadPos / 8; const int overlap = ReadPos % 8; + // A malformed frame can request more bits than it actually contains. + // Reading past the end of the buffer would be out-of-bounds access. + if (ReadPos + n > (int)Buf.size() * 8) + throw std::runtime_error("read past the end of the bitstream"); + + // Number of bytes the requested value actually spans, starting at bytesPos. + const int bytesToRead = (overlap + n + 7) / 8; + UBytes t; - for (int i = 0; i < n/8 + (overlap ? 2 : 1); ++i) { + for (int i = 0; i < bytesToRead; ++i) { #ifdef NBITSTREAM__LITTLE_ENDIAN_CPU t.bytes[3-i] = (uint8_t)Buf[bytesPos+i]; #else |
