Skip to content
2 changes: 1 addition & 1 deletion falco_plugin/src/async_event/async_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::ffi::c_char;
#[derive(Debug, Clone)]
pub struct AsyncHandler {
pub(crate) owner: *mut ss_plugin_owner_t,
pub(crate) raw_handler: unsafe extern "C-unwind" fn(
pub(crate) raw_handler: unsafe extern "C" fn(
o: *mut ss_plugin_owner_t,
evt: *const ss_plugin_event,
err: *mut c_char,
Expand Down
21 changes: 13 additions & 8 deletions falco_plugin/src/async_event/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::async_event::async_handler::AsyncHandler;
use crate::async_event::AsyncEventPlugin;
use crate::base::wrappers::PluginWrapper;
use crate::error::ffi_result::FfiResult;
use crate::error::panic::catch_panic;
use falco_plugin_api::plugin_api__bindgen_ty_4 as async_plugin_api;
use falco_plugin_api::{
ss_plugin_async_event_handler_t, ss_plugin_owner_t, ss_plugin_rc,
Expand All @@ -10,6 +11,7 @@ use falco_plugin_api::{
use std::any::TypeId;
use std::collections::BTreeMap;
use std::ffi::{c_char, CString};
use std::panic::AssertUnwindSafe;
use std::sync::Mutex;

/// Marker trait to mark an async plugin as exported to the API
Expand Down Expand Up @@ -50,8 +52,7 @@ impl<T: AsyncEventPlugin + 'static> AsyncPluginApi<T> {
pub const IMPLEMENTS_ASYNC: bool = true;
}

pub extern "C-unwind" fn plugin_get_async_event_sources<T: AsyncEventPlugin + 'static>(
) -> *const c_char {
pub extern "C" fn plugin_get_async_event_sources<T: AsyncEventPlugin + 'static>() -> *const c_char {
static SOURCES: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());

let ty = TypeId::of::<T>();
Expand All @@ -68,7 +69,7 @@ pub extern "C-unwind" fn plugin_get_async_event_sources<T: AsyncEventPlugin + 's
.as_ptr()
}

pub extern "C-unwind" fn plugin_get_async_events<T: AsyncEventPlugin + 'static>() -> *const c_char {
pub extern "C" fn plugin_get_async_events<T: AsyncEventPlugin + 'static>() -> *const c_char {
static EVENTS: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());

let ty = TypeId::of::<T>();
Expand All @@ -88,7 +89,7 @@ pub extern "C-unwind" fn plugin_get_async_events<T: AsyncEventPlugin + 'static>(
/// # Safety
///
/// All pointers must be valid
pub unsafe extern "C-unwind" fn plugin_set_async_event_handler<T: AsyncEventPlugin>(
pub unsafe extern "C" fn plugin_set_async_event_handler<T: AsyncEventPlugin>(
plugin: *mut ss_plugin_t,
owner: *mut ss_plugin_owner_t,
handler: ss_plugin_async_event_handler_t,
Expand All @@ -102,7 +103,7 @@ pub unsafe extern "C-unwind" fn plugin_set_async_event_handler<T: AsyncEventPlug
return ss_plugin_rc_SS_PLUGIN_FAILURE;
};

if let Err(e) = actual_plugin.plugin.stop_async() {
if let Err(e) = catch_panic(AssertUnwindSafe(|| actual_plugin.plugin.stop_async())) {
e.set_last_error(&mut plugin.error_buf);
return e.status_code();
}
Expand All @@ -115,7 +116,9 @@ pub unsafe extern "C-unwind" fn plugin_set_async_event_handler<T: AsyncEventPlug
owner,
raw_handler: *raw_handler,
};
if let Err(e) = actual_plugin.plugin.start_async(handler) {
if let Err(e) = catch_panic(AssertUnwindSafe(|| {
actual_plugin.plugin.start_async(handler)
})) {
e.set_last_error(&mut plugin.error_buf);
return e.status_code();
}
Expand All @@ -127,7 +130,7 @@ pub unsafe extern "C-unwind" fn plugin_set_async_event_handler<T: AsyncEventPlug
/// # Safety
///
/// All pointers must be valid
pub unsafe extern "C-unwind" fn plugin_dump_state<T: AsyncEventPlugin>(
pub unsafe extern "C" fn plugin_dump_state<T: AsyncEventPlugin>(
plugin: *mut ss_plugin_t,
owner: *mut ss_plugin_owner_t,
handler: ss_plugin_async_event_handler_t,
Expand All @@ -149,7 +152,9 @@ pub unsafe extern "C-unwind" fn plugin_dump_state<T: AsyncEventPlugin>(
owner,
raw_handler: *raw_handler,
};
if let Err(e) = actual_plugin.plugin.dump_state(handler) {
if let Err(e) = catch_panic(AssertUnwindSafe(|| {
actual_plugin.plugin.dump_state(handler)
})) {
e.set_last_error(&mut plugin.error_buf);
return e.status_code();
}
Expand Down
2 changes: 1 addition & 1 deletion falco_plugin/src/base/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::sync::RwLock;

pub(super) struct FalcoPluginLoggerImpl {
pub(super) owner: *mut ss_plugin_owner_t,
pub(super) logger_fn: unsafe extern "C-unwind" fn(
pub(super) logger_fn: unsafe extern "C" fn(
o: *mut ss_plugin_owner_t,
component: *const c_char,
msg: *const c_char,
Expand Down
107 changes: 62 additions & 45 deletions falco_plugin/src/base/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::base::schema::{ConfigSchema, ConfigSchemaType};
use crate::base::Plugin;
use crate::error::ffi_result::FfiResult;
use crate::error::last_error::LastError;
use crate::error::panic::catch_panic;
use crate::strings::from_ptr::try_str_from_ptr;
use crate::strings::WriteIntoCString;
use crate::tables::TablesInput;
Expand All @@ -15,6 +16,7 @@ use std::collections::BTreeMap;
use std::ffi::{c_char, CString};
use std::fmt::Display;
use std::io::Write;
use std::panic::AssertUnwindSafe;
use std::sync::Mutex;

/// Marker trait to mark a plugin as exported to the API
Expand All @@ -30,7 +32,7 @@ use std::sync::Mutex;
)]
pub unsafe trait BasePluginExported {}

pub extern "C-unwind" fn plugin_get_required_api_version<
pub extern "C" fn plugin_get_required_api_version<
const MAJOR: usize,
const MINOR: usize,
const PATCH: usize,
Expand All @@ -49,61 +51,63 @@ pub extern "C-unwind" fn plugin_get_required_api_version<
.as_ptr()
}

pub extern "C-unwind" fn plugin_get_version<T: Plugin>() -> *const c_char {
pub extern "C" fn plugin_get_version<T: Plugin>() -> *const c_char {
T::PLUGIN_VERSION.as_ptr()
}

pub extern "C-unwind" fn plugin_get_name<T: Plugin>() -> *const c_char {
pub extern "C" fn plugin_get_name<T: Plugin>() -> *const c_char {
T::NAME.as_ptr()
}

pub extern "C-unwind" fn plugin_get_description<T: Plugin>() -> *const c_char {
pub extern "C" fn plugin_get_description<T: Plugin>() -> *const c_char {
T::DESCRIPTION.as_ptr()
}

pub extern "C-unwind" fn plugin_get_contact<T: Plugin>() -> *const c_char {
pub extern "C" fn plugin_get_contact<T: Plugin>() -> *const c_char {
T::CONTACT.as_ptr()
}

/// # Safety
///
/// init_input must be null or a valid pointer
pub unsafe extern "C-unwind" fn plugin_init<P: Plugin>(
pub unsafe extern "C" fn plugin_init<P: Plugin>(
init_input: *const ss_plugin_init_input,
rc: *mut ss_plugin_rc,
) -> *mut falco_plugin_api::ss_plugin_t {
let res = (|| -> Result<*mut PluginWrapper<P>, anyhow::Error> {
let init_input = unsafe { init_input.as_ref() }
.ok_or_else(|| anyhow::anyhow!("Got empty init_input"))?;
let res = catch_panic(AssertUnwindSafe(
|| -> Result<*mut PluginWrapper<P>, anyhow::Error> {
let init_input = unsafe { init_input.as_ref() }
.ok_or_else(|| anyhow::anyhow!("Got empty init_input"))?;

let init_config =
try_str_from_ptr(&init_input.config).context("Failed to get config string")?;
let init_config =
try_str_from_ptr(&init_input.config).context("Failed to get config string")?;

let config = P::ConfigType::from_str(init_config).context("Failed to parse config")?;
if let Some(log_fn) = init_input.log_fn {
let logger_impl = FalcoPluginLoggerImpl {
owner: init_input.owner,
logger_fn: log_fn,
};
let config = P::ConfigType::from_str(init_config).context("Failed to parse config")?;
if let Some(log_fn) = init_input.log_fn {
let logger_impl = FalcoPluginLoggerImpl {
owner: init_input.owner,
logger_fn: log_fn,
};

*FALCO_LOGGER.inner.write().unwrap() = Some(logger_impl);
log::set_logger(&FALCO_LOGGER).ok();
*FALCO_LOGGER.inner.write().unwrap() = Some(logger_impl);
log::set_logger(&FALCO_LOGGER).ok();

#[cfg(debug_assertions)]
log::set_max_level(log::LevelFilter::Trace);
#[cfg(debug_assertions)]
log::set_max_level(log::LevelFilter::Trace);

#[cfg(not(debug_assertions))]
log::set_max_level(log::LevelFilter::Info);
}
#[cfg(not(debug_assertions))]
log::set_max_level(log::LevelFilter::Info);
}

let tables_input =
TablesInput::try_from(init_input).context("Failed to build tables input")?;
let tables_input =
TablesInput::try_from(init_input).context("Failed to build tables input")?;

let last_error = unsafe { LastError::from(init_input)? };
let last_error = unsafe { LastError::from(init_input)? };

P::new(tables_input.as_ref(), config)
.map(|plugin| Box::into_raw(Box::new(PluginWrapper::new(plugin, last_error))))
})();
P::new(tables_input.as_ref(), config)
.map(|plugin| Box::into_raw(Box::new(PluginWrapper::new(plugin, last_error))))
},
));

match res {
Ok(plugin) => {
Expand All @@ -127,7 +131,7 @@ pub unsafe extern "C-unwind" fn plugin_init<P: Plugin>(
/// # Safety
///
/// schema_type must be null or a valid pointer
pub unsafe extern "C-unwind" fn plugin_get_init_schema<P: Plugin>(
pub unsafe extern "C" fn plugin_get_init_schema<P: Plugin>(
schema_type: *mut falco_plugin_api::ss_plugin_schema_type,
) -> *const c_char {
let schema_type = unsafe {
Expand All @@ -151,19 +155,25 @@ pub unsafe extern "C-unwind" fn plugin_get_init_schema<P: Plugin>(
/// # Safety
///
/// `plugin` must have been created by `init()` and not destroyed since
pub unsafe extern "C-unwind" fn plugin_destroy<P: Plugin>(
plugin: *mut falco_plugin_api::ss_plugin_t,
) {
pub unsafe extern "C" fn plugin_destroy<P: Plugin>(plugin: *mut falco_plugin_api::ss_plugin_t) {
unsafe {
let plugin = plugin as *mut PluginWrapper<P>;
let _ = Box::from_raw(plugin);
match catch_panic(AssertUnwindSafe(|| {
let _ = Box::from_raw(plugin);
Ok(())
})) {
Ok(()) => {}
Err(e) => {
log::error!("Failed to destroy plugin: {e}");
}
}
}
}

/// # Safety
///
/// `plugin` must be a valid pointer to `PluginWrapper<P>`
pub unsafe extern "C-unwind" fn plugin_get_last_error<P: Plugin>(
pub unsafe extern "C" fn plugin_get_last_error<P: Plugin>(
plugin: *mut falco_plugin_api::ss_plugin_t,
) -> *const c_char {
let plugin = plugin as *mut PluginWrapper<P>;
Expand All @@ -173,7 +183,7 @@ pub unsafe extern "C-unwind" fn plugin_get_last_error<P: Plugin>(
}
}

pub unsafe extern "C-unwind" fn plugin_set_config<P: Plugin>(
pub unsafe extern "C" fn plugin_set_config<P: Plugin>(
plugin: *mut falco_plugin_api::ss_plugin_t,
config_input: *const falco_plugin_api::ss_plugin_set_config_input,
) -> falco_plugin_api::ss_plugin_rc {
Expand All @@ -189,20 +199,20 @@ pub unsafe extern "C-unwind" fn plugin_set_config<P: Plugin>(
return ss_plugin_rc_SS_PLUGIN_FAILURE;
};

let res = (|| -> Result<(), anyhow::Error> {
let res = catch_panic(AssertUnwindSafe(|| -> Result<(), anyhow::Error> {
let config_input = unsafe { config_input.as_ref() }.context("Got NULL config")?;

let updated_config =
try_str_from_ptr(&config_input.config).context("Failed to get config string")?;
let config = P::ConfigType::from_str(updated_config).context("Failed to parse config")?;

actual_plugin.plugin.set_config(config)
})();
}));

res.rc(&mut plugin.error_buf)
}

pub unsafe extern "C-unwind" fn plugin_get_metrics<P: Plugin>(
pub unsafe extern "C" fn plugin_get_metrics<P: Plugin>(
plugin: *mut ss_plugin_t,
num_metrics: *mut u32,
) -> *mut ss_plugin_metric {
Expand All @@ -228,15 +238,22 @@ pub unsafe extern "C-unwind" fn plugin_get_metrics<P: Plugin>(
};

plugin.metric_storage.clear();
for metric in actual_plugin.plugin.get_metrics() {
plugin.metric_storage.push(metric.as_raw());
if let Err(e) = catch_panic(AssertUnwindSafe(|| {
for metric in actual_plugin.plugin.get_metrics() {
plugin.metric_storage.push(metric.as_raw());
}
Ok(())
})) {
e.set_last_error(&mut plugin.error_buf);
*num_metrics = 0;
return std::ptr::null_mut();
}

*num_metrics = plugin.metric_storage.len() as u32;
plugin.metric_storage.as_ptr().cast_mut()
}

pub extern "C-unwind" fn plugin_get_required_event_schema_version<T: Plugin>(
pub extern "C" fn plugin_get_required_event_schema_version<T: Plugin>(
_plugin: *mut ss_plugin_t,
) -> *const c_char {
T::SCHEMA_VERSION.as_ptr()
Expand All @@ -253,7 +270,7 @@ macro_rules! wrap_ffi {
) => {
$(
#[$attr]
pub unsafe extern "C-unwind" fn $name ( $($param: $param_ty),*) -> $ret {
pub unsafe extern "C" fn $name ( $($param: $param_ty),*) -> $ret {
use $mod as wrappers;

wrappers::$name::<$ty>($($param),*)
Expand Down Expand Up @@ -525,7 +542,7 @@ macro_rules! ensure_plugin_capabilities {
macro_rules! base_plugin_ffi_wrappers {
($maj:expr; $min:expr; $patch:expr => #[$attr:meta] $ty:ty) => {
#[$attr]
pub extern "C-unwind" fn plugin_get_required_api_version() -> *const std::ffi::c_char {
pub extern "C" fn plugin_get_required_api_version() -> *const std::ffi::c_char {
$crate::base::wrappers::plugin_get_required_api_version::<
{ $maj },
{ $min },
Expand Down
4 changes: 2 additions & 2 deletions falco_plugin/src/error/last_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use std::ffi::c_char;
#[derive(Clone, Debug)]
pub struct LastError {
owner: *mut ss_plugin_owner_t,
get_owner_last_error: unsafe extern "C-unwind" fn(o: *mut ss_plugin_owner_t) -> *const c_char,
get_owner_last_error: unsafe extern "C" fn(o: *mut ss_plugin_owner_t) -> *const c_char,
}

impl LastError {
pub unsafe fn new(
owner: *mut ss_plugin_owner_t,
get_owner_last_error: unsafe extern "C-unwind" fn(*mut ss_plugin_owner_t) -> *const c_char,
get_owner_last_error: unsafe extern "C" fn(*mut ss_plugin_owner_t) -> *const c_char,
) -> Self {
Self {
owner,
Expand Down
1 change: 1 addition & 0 deletions falco_plugin/src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod as_result;
pub mod ffi_result;
pub mod last_error;
pub mod panic;

use thiserror::Error;

Expand Down
19 changes: 19 additions & 0 deletions falco_plugin/src/error/panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::panic::UnwindSafe;

pub(crate) fn catch_panic<T, F>(f: F) -> Result<T, anyhow::Error>
where
F: UnwindSafe + FnOnce() -> Result<T, anyhow::Error>,
{
// Call `f` explicitly so debuggers can step into the closure body
// before entering std's catch_unwind machinery.
#[allow(clippy::redundant_closure)]
std::panic::catch_unwind(move || f()).unwrap_or_else(|e| {
if let Some(e) = e.downcast_ref::<&'static str>() {
Err(anyhow::anyhow!("{}", e))
} else if let Some(e) = e.downcast_ref::<String>() {
Err(anyhow::anyhow!("{}", e))
} else {
Err(anyhow::anyhow!("panic"))
}
})
}
Loading
Loading