Skip to content

Commit

Permalink
Fix in-place checks in buffer management
Browse files Browse the repository at this point in the history
The previous implementation didn't work correctly, and would thus result
in soundness issues. Rust 1.78 finally fixes debug assertions in the
standard library so this was caught immediately.
  • Loading branch information
robbert-vdh committed May 4, 2024
1 parent 10aabe3 commit d270d12
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 15 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,13 @@ Since there is no stable release yet, the changes are organized per day in
reverse chronological order. The main purpose of this document in its current
state is to list breaking changes.

## [2024-05-04]

### Fixed

- Fixed a soundness issue in the buffer management where in-place input/output
buffers may not have been recognized properly before.

## [2024-03-23]

### Added
Expand Down
34 changes: 19 additions & 15 deletions src/wrapper/util/buffer_management.rs
Expand Up @@ -51,6 +51,7 @@ unsafe impl Sync for BufferManager {}

/// Host data that the plugin's [`Buffer`]s should be created from. Leave these fields as `None`
/// values
#[derive(Debug)]
pub struct BufferSource<'a> {
pub main_input_channel_pointers: &'a mut Option<ChannelPointers>,
pub main_output_channel_pointers: &'a mut Option<ChannelPointers>,
Expand Down Expand Up @@ -219,25 +220,28 @@ impl BufferManager {
self.main_input_channel_pointers,
self.main_output_channel_pointers,
) {
// If the host processes the main IO out of place then the inputs need to be copied to
// the output buffers. Otherwise the input should already be there.
if input_channel_pointers.ptrs != output_channel_pointers.ptrs {
self.main_buffer.set_slices(num_samples, |output_slices| {
for (channel_idx, output_slice) in output_slices
.iter_mut()
.enumerate()
.take(input_channel_pointers.num_channels)
{
let input_channel_pointer =
input_channel_pointers.ptrs.as_ptr().add(channel_idx);

self.main_buffer.set_slices(num_samples, |output_slices| {
for (channel_idx, output_slice) in output_slices
.iter_mut()
.enumerate()
.take(input_channel_pointers.num_channels)
{
let input_channel_pointer =
*input_channel_pointers.ptrs.as_ptr().add(channel_idx);
debug_assert!(channel_idx < output_channel_pointers.num_channels);
let output_channel_pointer =
*output_channel_pointers.ptrs.as_ptr().add(channel_idx);

// If the host processes the main IO out of place then the inputs need to be
// copied to the output buffers. Otherwise the input should already be there.
if input_channel_pointer != output_channel_pointer {
output_slice.copy_from_slice(std::slice::from_raw_parts_mut(
(*input_channel_pointer).add(sample_offset),
input_channel_pointer.add(sample_offset),
num_samples,
))
}
});
}
}
});

// Any excess channels will need to be filled with zeroes since they'd otherwise point
// to whatever was left in the buffer
Expand Down

0 comments on commit d270d12

Please sign in to comment.