Add consistent null pointer checks to CLAP wrapper
Just like we do for the VST3 wrapper.
This commit is contained in:
parent
66012f9787
commit
78b815fede
3 changed files with 40 additions and 27 deletions
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue