diff options
| author | 2023-06-30 00:54:23 -0400 | |
|---|---|---|
| committer | 2023-06-30 00:54:23 -0400 | |
| commit | ea8d5ef5e81861e013b5c58189faeffe7d3a6f18 (patch) | |
| tree | ae781e60097b06182a9cb8cd06434d049fc0f0a0 | |
| parent | Merge pull request #10955 from 8bitDream/gradle (diff) | |
| download | yuzu-ea8d5ef5e81861e013b5c58189faeffe7d3a6f18.tar.gz yuzu-ea8d5ef5e81861e013b5c58189faeffe7d3a6f18.tar.xz yuzu-ea8d5ef5e81861e013b5c58189faeffe7d3a6f18.zip | |
sink_stream: Resolve heap buffer corruption due to out of bounds write
Also, remove the use of ScratchBuffer when upmixing, as other channels may not be initialized with zeroed out data.
| -rw-r--r-- | src/audio_core/sink/sink_stream.cpp | 34 | ||||
| -rw-r--r-- | src/audio_core/sink/sink_stream.h | 3 |
2 files changed, 20 insertions, 17 deletions
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 404dcd0e9..6081352a2 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "audio_core/sink/sink_stream.h" | 12 | #include "audio_core/sink/sink_stream.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/fixed_point.h" | 14 | #include "common/fixed_point.h" |
| 15 | #include "common/scope_exit.h" | ||
| 15 | #include "common/settings.h" | 16 | #include "common/settings.h" |
| 16 | #include "core/core.h" | 17 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| @@ -19,9 +20,12 @@ | |||
| 19 | namespace AudioCore::Sink { | 20 | namespace AudioCore::Sink { |
| 20 | 21 | ||
| 21 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { | 22 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { |
| 22 | if (type == StreamType::In) { | 23 | SCOPE_EXIT({ |
| 23 | queue.enqueue(buffer); | 24 | queue.enqueue(buffer); |
| 24 | queued_buffers++; | 25 | ++queued_buffers; |
| 26 | }); | ||
| 27 | |||
| 28 | if (type == StreamType::In) { | ||
| 25 | return; | 29 | return; |
| 26 | } | 30 | } |
| 27 | 31 | ||
| @@ -66,16 +70,17 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { | |||
| 66 | static_cast<s16>(std::clamp(right_sample, min, max)); | 70 | static_cast<s16>(std::clamp(right_sample, min, max)); |
| 67 | } | 71 | } |
| 68 | 72 | ||
| 69 | samples = samples.subspan(0, samples.size() / system_channels * device_channels); | 73 | samples_buffer.Push(samples.subspan(0, samples.size() / system_channels * device_channels)); |
| 74 | return; | ||
| 75 | } | ||
| 70 | 76 | ||
| 71 | } else if (system_channels == 2 && device_channels == 6) { | 77 | if (system_channels == 2 && device_channels == 6) { |
| 72 | // We need moar samples! Not all games will provide 6 channel audio. | 78 | // We need moar samples! Not all games will provide 6 channel audio. |
| 73 | // TODO: Implement some upmixing here. Currently just passthrough, with other | 79 | // TODO: Implement some upmixing here. Currently just passthrough, with other |
| 74 | // channels left as silence. | 80 | // channels left as silence. |
| 75 | auto new_size = samples.size() / system_channels * device_channels; | 81 | std::vector<s16> new_samples(samples.size() / system_channels * device_channels); |
| 76 | tmp_samples.resize_destructive(new_size); | ||
| 77 | 82 | ||
| 78 | for (u32 read_index = 0, write_index = 0; read_index < new_size; | 83 | for (u32 read_index = 0, write_index = 0; read_index < samples.size(); |
| 79 | read_index += system_channels, write_index += device_channels) { | 84 | read_index += system_channels, write_index += device_channels) { |
| 80 | const auto left_sample{static_cast<s16>(std::clamp( | 85 | const auto left_sample{static_cast<s16>(std::clamp( |
| 81 | static_cast<s32>( | 86 | static_cast<s32>( |
| @@ -83,7 +88,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { | |||
| 83 | volume), | 88 | volume), |
| 84 | min, max))}; | 89 | min, max))}; |
| 85 | 90 | ||
| 86 | tmp_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample; | 91 | new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample; |
| 87 | 92 | ||
| 88 | const auto right_sample{static_cast<s16>(std::clamp( | 93 | const auto right_sample{static_cast<s16>(std::clamp( |
| 89 | static_cast<s32>( | 94 | static_cast<s32>( |
| @@ -91,20 +96,21 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { | |||
| 91 | volume), | 96 | volume), |
| 92 | min, max))}; | 97 | min, max))}; |
| 93 | 98 | ||
| 94 | tmp_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample; | 99 | new_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample; |
| 95 | } | 100 | } |
| 96 | samples = std::span<s16>(tmp_samples); | ||
| 97 | 101 | ||
| 98 | } else if (volume != 1.0f) { | 102 | samples_buffer.Push(new_samples); |
| 99 | for (u32 i = 0; i < samples.size(); i++) { | 103 | return; |
| 104 | } | ||
| 105 | |||
| 106 | if (volume != 1.0f) { | ||
| 107 | for (u32 i = 0; i < samples.size(); ++i) { | ||
| 100 | samples[i] = static_cast<s16>( | 108 | samples[i] = static_cast<s16>( |
| 101 | std::clamp(static_cast<s32>(static_cast<f32>(samples[i]) * volume), min, max)); | 109 | std::clamp(static_cast<s32>(static_cast<f32>(samples[i]) * volume), min, max)); |
| 102 | } | 110 | } |
| 103 | } | 111 | } |
| 104 | 112 | ||
| 105 | samples_buffer.Push(samples); | 113 | samples_buffer.Push(samples); |
| 106 | queue.enqueue(buffer); | ||
| 107 | queued_buffers++; | ||
| 108 | } | 114 | } |
| 109 | 115 | ||
| 110 | std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) { | 116 | std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) { |
diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 98d72ace1..6a4996ca3 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include "common/polyfill_thread.h" | 16 | #include "common/polyfill_thread.h" |
| 17 | #include "common/reader_writer_queue.h" | 17 | #include "common/reader_writer_queue.h" |
| 18 | #include "common/ring_buffer.h" | 18 | #include "common/ring_buffer.h" |
| 19 | #include "common/scratch_buffer.h" | ||
| 20 | #include "common/thread.h" | 19 | #include "common/thread.h" |
| 21 | 20 | ||
| 22 | namespace Core { | 21 | namespace Core { |
| @@ -256,8 +255,6 @@ private: | |||
| 256 | /// Signalled when ring buffer entries are consumed | 255 | /// Signalled when ring buffer entries are consumed |
| 257 | std::condition_variable_any release_cv; | 256 | std::condition_variable_any release_cv; |
| 258 | std::mutex release_mutex; | 257 | std::mutex release_mutex; |
| 259 | /// Temporary buffer for appending samples when upmixing | ||
| 260 | Common::ScratchBuffer<s16> tmp_samples{}; | ||
| 261 | }; | 258 | }; |
| 262 | 259 | ||
| 263 | using SinkStreamPtr = std::unique_ptr<SinkStream>; | 260 | using SinkStreamPtr = std::unique_ptr<SinkStream>; |