summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/factories/naudio/v0/AIFCDecode.cpp17
-rw-r--r--src/factories/naudio/v0/SampleFactory.cpp24
-rw-r--r--src/factories/naudio/v1/AudioConverter.cpp11
-rw-r--r--src/factories/naudio/v1/SequencePlayerV1.cpp48
4 files changed, 68 insertions, 32 deletions
diff --git a/src/factories/naudio/v0/AIFCDecode.cpp b/src/factories/naudio/v0/AIFCDecode.cpp
index 3782d98..95ed57e 100644
--- a/src/factories/naudio/v0/AIFCDecode.cpp
+++ b/src/factories/naudio/v0/AIFCDecode.cpp
@@ -112,7 +112,22 @@ typedef struct {
s16 state[16];
} ALADPCMloop;
-#define checked_fread(a, b, c, d) d.Read((char*)a, b* c)
+NORETURN
+void fail_parse(const char* fmt, ...);
+
+// Bounds-checked read: refuses to read past the end of the underlying buffer,
+// turning malformed/truncated input into a catchable parse error instead of a
+// heap-buffer-overflow.
+static void checked_read(LUS::BinaryReader& reader, void* dst, size_t len) {
+ size_t pos = reader.GetBaseAddress();
+ size_t length = reader.GetLength();
+ if (pos > length || len > length - pos) {
+ fail_parse("unexpected end of file while reading %zu bytes at offset %zu", len, pos);
+ }
+ reader.Read((char*)dst, (int32_t)len);
+}
+
+#define checked_fread(a, b, c, d) checked_read(d, (void*)(a), (size_t)(b) * (size_t)(c))
NORETURN
void fail_parse(const char* fmt, ...) {
diff --git a/src/factories/naudio/v0/SampleFactory.cpp b/src/factories/naudio/v0/SampleFactory.cpp
index 7f1898d..5860cff 100644
--- a/src/factories/naudio/v0/SampleFactory.cpp
+++ b/src/factories/naudio/v0/SampleFactory.cpp
@@ -164,16 +164,22 @@ bool DecodeAiffBytes(const std::vector<char>& bytes, std::vector<int16_t>& pcm,
}
bool DecodeSampleToPcm(AudioBankSample* sample, std::vector<int16_t>& pcm, int& rate) {
- LUS::BinaryWriter aifc;
- AudioConverter::SampleV0ToAIFC(sample, aifc);
- LUS::BinaryWriter aiff;
- write_aiff(aifc.ToVector(), aiff);
- aifc.Close();
-
DecodedSample decoded;
- const bool ok = ParseAiff(aiff.ToVector(), decoded);
- aiff.Close();
- if (!ok) {
+ try {
+ LUS::BinaryWriter aifc;
+ AudioConverter::SampleV0ToAIFC(sample, aifc);
+ LUS::BinaryWriter aiff;
+ // write_aiff throws std::runtime_error on malformed/truncated sample data.
+ write_aiff(aifc.ToVector(), aiff);
+ aifc.Close();
+
+ const bool ok = ParseAiff(aiff.ToVector(), decoded);
+ aiff.Close();
+ if (!ok) {
+ return false;
+ }
+ } catch (const std::exception& e) {
+ SPDLOG_ERROR("Failed to decode audio sample: {}", e.what());
return false;
}
// The converter's header overwrites the head of the decoded stream; pad the
diff --git a/src/factories/naudio/v1/AudioConverter.cpp b/src/factories/naudio/v1/AudioConverter.cpp
index 59bbd3c..910ae8c 100644
--- a/src/factories/naudio/v1/AudioConverter.cpp
+++ b/src/factories/naudio/v1/AudioConverter.cpp
@@ -152,10 +152,13 @@ void AudioConverter::SampleV0ToAIFC(AudioBankSample* sample, LUS::BinaryWriter&
vloops.Write(sample->loop.end);
vloops.Write(sample->loop.count);
- if (sample->loop.state.has_value()) {
- for (auto state : sample->loop.state.value()) {
- vcodes.Write(state);
- }
+ // The decoder reads back a fixed-size ALADPCMloop whose state is a
+ // 16-entry array; always emit all 16 (zero-filled when absent) so the
+ // chunk is exactly 44 bytes. Note: this must target vloops, not vcodes.
+ const std::vector<int16_t>* state =
+ sample->loop.state.has_value() ? &sample->loop.state.value() : nullptr;
+ for (size_t i = 0; i < 16; i++) {
+ vloops.Write((int16_t)(state != nullptr && i < state->size() ? (*state)[i] : 0));
}
aifc.End("APPL", vloops);
}
diff --git a/src/factories/naudio/v1/SequencePlayerV1.cpp b/src/factories/naudio/v1/SequencePlayerV1.cpp
index e48bb93..881ab3a 100644
--- a/src/factories/naudio/v1/SequencePlayerV1.cpp
+++ b/src/factories/naudio/v1/SequencePlayerV1.cpp
@@ -234,19 +234,25 @@ std::shared_ptr<UI::SynthSample> SynthSampleFor(NSampleData* sample) {
AudioConverter::SampleV1ToAIFC(sample, lit0->second, bit->second, aifc);
const auto bytes = aifc.ToVector();
if (!bytes.empty()) {
- LUS::BinaryWriter aiff;
- write_aiff(bytes, aiff);
- int rate = 0;
- const bool ok = DecodeAiffBytes(aiff.ToVector(), synth->pcm, rate);
- if ((!ok || synth->pcm.empty()) && std::getenv("TORCH_SEQ_DEBUG") != nullptr) {
- printf("[sample] DECODE FAIL addr=0x%X book(order=%d npred=%d coeffs=%zu) loop(%u..%u x%u) aifc=%zu\n",
- sample->sampleAddr, bit->second->order, bit->second->numPredictors, bit->second->book.size(),
- lit0->second->start, lit0->second->end, lit0->second->count, bytes.size());
- }
- aiff.Close();
- const size_t expected = (size_t)sample->size * 16 / 9;
- if (synth->pcm.size() < expected) {
- synth->pcm.insert(synth->pcm.begin(), expected - synth->pcm.size(), 0);
+ try {
+ LUS::BinaryWriter aiff;
+ // write_aiff throws std::runtime_error on malformed/truncated sample data.
+ write_aiff(bytes, aiff);
+ int rate = 0;
+ const bool ok = DecodeAiffBytes(aiff.ToVector(), synth->pcm, rate);
+ if ((!ok || synth->pcm.empty()) && std::getenv("TORCH_SEQ_DEBUG") != nullptr) {
+ printf("[sample] DECODE FAIL addr=0x%X book(order=%d npred=%d coeffs=%zu) loop(%u..%u x%u) aifc=%zu\n",
+ sample->sampleAddr, bit->second->order, bit->second->numPredictors, bit->second->book.size(),
+ lit0->second->start, lit0->second->end, lit0->second->count, bytes.size());
+ }
+ aiff.Close();
+ const size_t expected = (size_t)sample->size * 16 / 9;
+ if (synth->pcm.size() < expected) {
+ synth->pcm.insert(synth->pcm.begin(), expected - synth->pcm.size(), 0);
+ }
+ } catch (const std::exception& e) {
+ SPDLOG_ERROR("Failed to decode audio sample at addr 0x{:X}: {}", sample->sampleAddr, e.what());
+ synth->pcm.clear();
}
}
aifc.Close();
@@ -1408,11 +1414,17 @@ bool DecodeV1SampleToPcm(const ParseResultData& item, std::vector<int16_t>& pcm,
if (bytes.empty()) {
return false;
}
- LUS::BinaryWriter aiff;
- write_aiff(bytes, aiff);
- const bool ok = DecodeAiffBytes(aiff.ToVector(), pcm, rate);
- aiff.Close();
- return ok && !pcm.empty();
+ try {
+ LUS::BinaryWriter aiff;
+ // write_aiff throws std::runtime_error on malformed/truncated sample data.
+ write_aiff(bytes, aiff);
+ const bool ok = DecodeAiffBytes(aiff.ToVector(), pcm, rate);
+ aiff.Close();
+ return ok && !pcm.empty();
+ } catch (const std::exception& e) {
+ SPDLOG_ERROR("Failed to decode audio sample at addr 0x{:X}: {}", sample->sampleAddr, e.what());
+ return false;
+ }
}
bool SequencePlayerV1::Render(const ParseResultData& item, int, UI::RenderedAudio& out) {