1
0
Fork 0

Add consistent null pointer checks to CLAP wrapper

Just like we do for the VST3 wrapper.
This commit is contained in:
Robbert van der Helm 2022-03-02 14:25:26 +01:00
parent 66012f9787
commit 78b815fede
3 changed files with 40 additions and 27 deletions

View file

@ -1,8 +1,10 @@
#[macro_use]
mod util;
mod context; mod context;
mod descriptor; mod descriptor;
mod factory; mod factory;
mod plugin; mod plugin;
mod util;
/// Re-export for the wrapper. /// Re-export for the wrapper.
pub use self::factory::Factory; pub use self::factory::Factory;

View file

@ -1,3 +1,7 @@
// Clippy doesn't understand it when we use a unit in our `check_null_ptr!()` maccro, even if we
// explicitly pattern match on that unit
#![allow(clippy::unused_unit)]
use clap_sys::events::{ use clap_sys::events::{
clap_event_header, clap_event_note, clap_event_param_mod, clap_event_param_value, clap_event_header, clap_event_note, clap_event_param_mod, clap_event_param_value,
clap_input_events, clap_output_events, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI, clap_input_events, clap_output_events, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI,
@ -483,12 +487,9 @@ impl<P: ClapPlugin> Wrapper<P> {
plugin: *const clap_plugin, plugin: *const clap_plugin,
process: *const clap_process, process: *const clap_process,
) -> clap_process_status { ) -> clap_process_status {
check_null_ptr!(CLAP_PROCESS_ERROR, plugin, process);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if process.is_null() {
return CLAP_PROCESS_ERROR;
}
// Panic on allocations if the `assert_process_allocs` feature has been enabled, and make // Panic on allocations if the `assert_process_allocs` feature has been enabled, and make
// sure that FTZ is set up correctly // sure that FTZ is set up correctly
process_wrapper(|| { process_wrapper(|| {
@ -525,7 +526,12 @@ impl<P: ClapPlugin> Wrapper<P> {
); );
// Right now we don't handle any auxiliary outputs // Right now we don't handle any auxiliary outputs
nih_debug_assert!(!process.audio_outputs.is_null()); check_null_ptr_msg!(
"Null pointers passed for audio outputs in process function",
CLAP_PROCESS_ERROR,
process.audio_outputs,
(*process.audio_outputs).data32
);
let audio_outputs = &*process.audio_outputs; let audio_outputs = &*process.audio_outputs;
let num_output_channels = audio_outputs.channel_count as usize; let num_output_channels = audio_outputs.channel_count as usize;
@ -536,7 +542,6 @@ impl<P: ClapPlugin> Wrapper<P> {
// flags? // flags?
let mut output_buffer = wrapper.output_buffer.write(); let mut output_buffer = wrapper.output_buffer.write();
output_buffer.with_raw_vec(|output_slices| { output_buffer.with_raw_vec(|output_slices| {
nih_debug_assert!(!audio_outputs.data32.is_null());
nih_debug_assert_eq!(num_output_channels, output_slices.len()); nih_debug_assert_eq!(num_output_channels, output_slices.len());
for (output_channel_idx, output_channel_slice) in for (output_channel_idx, output_channel_slice) in
output_slices.iter_mut().enumerate() output_slices.iter_mut().enumerate()
@ -597,12 +602,9 @@ impl<P: ClapPlugin> Wrapper<P> {
plugin: *const clap_plugin, plugin: *const clap_plugin,
id: *const c_char, id: *const c_char,
) -> *const c_void { ) -> *const c_void {
check_null_ptr!(ptr::null(), plugin, id);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if id.is_null() {
return ptr::null();
}
// TODO: Implement the other useful extensions. Like uh audio inputs. // TODO: Implement the other useful extensions. Like uh audio inputs.
let id = CStr::from_ptr(id); let id = CStr::from_ptr(id);
if id == CStr::from_ptr(CLAP_EXT_PARAMS) { if id == CStr::from_ptr(CLAP_EXT_PARAMS) {
@ -623,6 +625,7 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
unsafe extern "C" fn ext_params_count(plugin: *const clap_plugin) -> u32 { unsafe extern "C" fn ext_params_count(plugin: *const clap_plugin) -> u32 {
check_null_ptr!(0, plugin);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
// NOTE: We add a bypass parameter ourselves on index `plugin.param_hashes.len()`, so // NOTE: We add a bypass parameter ourselves on index `plugin.param_hashes.len()`, so
@ -635,13 +638,11 @@ impl<P: ClapPlugin> Wrapper<P> {
param_index: i32, param_index: i32,
param_info: *mut clap_param_info, param_info: *mut clap_param_info,
) -> bool { ) -> bool {
check_null_ptr!(false, plugin, param_info);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
// Parameter index `self.param_ids.len()` is our own bypass parameter // Parameter index `self.param_ids.len()` is our own bypass parameter
if param_info.is_null() if param_index < 0 || param_index > wrapper.param_hashes.len() as i32 {
|| param_index < 0
|| param_index > wrapper.param_hashes.len() as i32
{
return false; return false;
} }
@ -694,12 +695,9 @@ impl<P: ClapPlugin> Wrapper<P> {
param_id: clap_id, param_id: clap_id,
value: *mut f64, value: *mut f64,
) -> bool { ) -> bool {
check_null_ptr!(false, plugin, value);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if value.is_null() {
return false;
}
if param_id == *BYPASS_PARAM_HASH { if param_id == *BYPASS_PARAM_HASH {
*value = if wrapper.bypass_state.load(Ordering::SeqCst) { *value = if wrapper.bypass_state.load(Ordering::SeqCst) {
1.0 1.0
@ -724,12 +722,9 @@ impl<P: ClapPlugin> Wrapper<P> {
display: *mut c_char, display: *mut c_char,
size: u32, size: u32,
) -> bool { ) -> bool {
check_null_ptr!(false, plugin, display);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if display.is_null() {
return false;
}
let dest = std::slice::from_raw_parts_mut(display, size as usize); let dest = std::slice::from_raw_parts_mut(display, size as usize);
if param_id == *BYPASS_PARAM_HASH { if param_id == *BYPASS_PARAM_HASH {
@ -762,12 +757,9 @@ impl<P: ClapPlugin> Wrapper<P> {
display: *const c_char, display: *const c_char,
value: *mut f64, value: *mut f64,
) -> bool { ) -> bool {
check_null_ptr!(false, plugin, display, value);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if display.is_null() || value.is_null() {
return false;
}
let display = match CStr::from_ptr(display).to_str() { let display = match CStr::from_ptr(display).to_str() {
Ok(s) => s, Ok(s) => s,
Err(_) => return false, Err(_) => return false,
@ -800,6 +792,7 @@ impl<P: ClapPlugin> Wrapper<P> {
in_: *const clap_input_events, in_: *const clap_input_events,
out: *const clap_output_events, out: *const clap_output_events,
) { ) {
check_null_ptr!((), plugin);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);
if !in_.is_null() { if !in_.is_null() {

View file

@ -1,5 +1,23 @@
use std::ops::Deref; use std::ops::Deref;
/// Early exit out of a function with the specified return value when one of the passed pointers is
/// null.
macro_rules! check_null_ptr {
($ret:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => {
check_null_ptr_msg!("Null pointer passed to function", $ret, $ptr $(, $ptrs)*)
};
}
/// The same as [check_null_ptr!], but with a custom message.
macro_rules! check_null_ptr_msg {
($msg:expr, $ret:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => {
if $ptr.is_null() $(|| $ptrs.is_null())* {
nih_debug_assert_failure!($msg);
return $ret;
}
};
}
/// Send+Sync wrapper around CLAP host extension pointers. /// Send+Sync wrapper around CLAP host extension pointers.
pub struct ClapPtr<T> { pub struct ClapPtr<T> {
inner: *const T, inner: *const T,