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 descriptor;
mod factory;
mod plugin;
mod util;
/// Re-export for the wrapper.
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::{
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,
@ -483,12 +487,9 @@ impl<P: ClapPlugin> Wrapper<P> {
plugin: *const clap_plugin,
process: *const clap_process,
) -> clap_process_status {
check_null_ptr!(CLAP_PROCESS_ERROR, plugin, process);
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
// sure that FTZ is set up correctly
process_wrapper(|| {
@ -525,7 +526,12 @@ impl<P: ClapPlugin> Wrapper<P> {
);
// 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 num_output_channels = audio_outputs.channel_count as usize;
@ -536,7 +542,6 @@ impl<P: ClapPlugin> Wrapper<P> {
// flags?
let mut output_buffer = wrapper.output_buffer.write();
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());
for (output_channel_idx, output_channel_slice) in
output_slices.iter_mut().enumerate()
@ -597,12 +602,9 @@ impl<P: ClapPlugin> Wrapper<P> {
plugin: *const clap_plugin,
id: *const c_char,
) -> *const c_void {
check_null_ptr!(ptr::null(), plugin, id);
let wrapper = &*(plugin as *const Self);
if id.is_null() {
return ptr::null();
}
// TODO: Implement the other useful extensions. Like uh audio inputs.
let id = CStr::from_ptr(id);
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 {
check_null_ptr!(0, plugin);
let wrapper = &*(plugin as *const Self);
// 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_info: *mut clap_param_info,
) -> bool {
check_null_ptr!(false, plugin, param_info);
let wrapper = &*(plugin as *const Self);
// Parameter index `self.param_ids.len()` is our own bypass parameter
if param_info.is_null()
|| param_index < 0
|| param_index > wrapper.param_hashes.len() as i32
{
if param_index < 0 || param_index > wrapper.param_hashes.len() as i32 {
return false;
}
@ -694,12 +695,9 @@ impl<P: ClapPlugin> Wrapper<P> {
param_id: clap_id,
value: *mut f64,
) -> bool {
check_null_ptr!(false, plugin, value);
let wrapper = &*(plugin as *const Self);
if value.is_null() {
return false;
}
if param_id == *BYPASS_PARAM_HASH {
*value = if wrapper.bypass_state.load(Ordering::SeqCst) {
1.0
@ -724,12 +722,9 @@ impl<P: ClapPlugin> Wrapper<P> {
display: *mut c_char,
size: u32,
) -> bool {
check_null_ptr!(false, plugin, display);
let wrapper = &*(plugin as *const Self);
if display.is_null() {
return false;
}
let dest = std::slice::from_raw_parts_mut(display, size as usize);
if param_id == *BYPASS_PARAM_HASH {
@ -762,12 +757,9 @@ impl<P: ClapPlugin> Wrapper<P> {
display: *const c_char,
value: *mut f64,
) -> bool {
check_null_ptr!(false, plugin, display, value);
let wrapper = &*(plugin as *const Self);
if display.is_null() || value.is_null() {
return false;
}
let display = match CStr::from_ptr(display).to_str() {
Ok(s) => s,
Err(_) => return false,
@ -800,6 +792,7 @@ impl<P: ClapPlugin> Wrapper<P> {
in_: *const clap_input_events,
out: *const clap_output_events,
) {
check_null_ptr!((), plugin);
let wrapper = &*(plugin as *const Self);
if !in_.is_null() {

View file

@ -1,5 +1,23 @@
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.
pub struct ClapPtr<T> {
inner: *const T,