Skip to content

Commit 2f5b0e3

Browse files
committed
rust/ffi: use ThreadVars wrapper in thread init callback
Update the thread init callback registration to pass the safe ThreadVars wrapper instead of a raw pointer. Ticket: OISF#8598
1 parent 419de42 commit 2f5b0e3

3 files changed

Lines changed: 25 additions & 28 deletions

File tree

doc/userguide/devguide/extending/threads.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,30 @@ Thread Init Callback
1111
====================
1212

1313
Register a callback with ``thread::register_init_callback`` to run code for
14-
each Suricata thread as it is initialized. The callback receives a raw
15-
``ThreadVars`` pointer for the thread that has just been initialized.
14+
each Suricata thread as it is initialized. The callback receives a
15+
``ThreadVars`` wrapper for the thread that has just been initialized.
1616

1717
The current Rust thread lifecycle API exposes an init callback only; there is
1818
no Rust thread deinit callback.
1919

2020
.. code-block:: rust
2121
22-
use suricata_ffi::thread;
22+
use suricata_ffi::thread::{self, ThreadVars};
2323
use suricata_ffi::SCLogNotice;
24-
use suricata_sys::sys::ThreadVars;
2524
26-
fn on_thread_init(tv: *mut ThreadVars) {
27-
SCLogNotice!("thread initialized: {:p}", tv);
25+
fn on_thread_init(tv: &mut ThreadVars) {
26+
SCLogNotice!("thread initialized: {:p}", tv.as_ptr());
2827
}
2928
3029
fn register_thread_callbacks() -> Result<(), &'static str> {
3130
thread::register_init_callback(on_thread_init)
3231
}
3332
3433
The wrapper accepts function items or closures that implement
35-
``Fn(*mut ThreadVars) + Send + Sync + 'static`` and returns
34+
``Fn(&mut ThreadVars) + Send + Sync + 'static`` and returns
3635
``Result<(), &'static str>``. An error means the callback could not be
3736
registered. Registered callbacks are kept for the Suricata process lifetime.
3837

39-
The ``ThreadVars`` pointer is only valid for the duration of the callback
40-
invocation and must not be stored. Rust callbacks must not panic.
38+
``ThreadVars`` carries a lifetime tied to the callback invocation, so the
39+
borrow checker prevents it from being stored beyond the call. Rust callbacks
40+
must not panic, as they are invoked across an FFI boundary.

examples/plugins/rust/src/mod.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::ptr::null_mut;
33
use suricata_ffi::eve::{self, SCJsonBuilder};
44
use suricata_ffi::flow;
55
use suricata_ffi::jsonbuilder::JsonBuilder;
6-
use suricata_ffi::thread;
6+
use suricata_ffi::thread::{self, ThreadVars};
77
use suricata_ffi::{SCLogError, SCLogNotice};
8-
use suricata_sys::sys::{Flow, Packet, SCEveRegisterCallback, SCPlugin, ThreadVars};
8+
use suricata_sys::sys::{self, Flow, Packet, SCEveRegisterCallback, SCPlugin};
99

1010
unsafe extern "C" fn init() {
1111
suricata_ffi::plugin::init();
@@ -41,7 +41,7 @@ pub fn register_thread_callbacks() -> Result<(), &'static str> {
4141
}
4242

4343
unsafe extern "C" fn log_eve_raw(
44-
_tv: *mut ThreadVars,
44+
_tv: *mut sys::ThreadVars,
4545
_p: *const Packet,
4646
_f: *mut Flow,
4747
jb: *mut SCJsonBuilder,
@@ -54,7 +54,7 @@ unsafe extern "C" fn log_eve_raw(
5454
}
5555

5656
fn log_eve_wrapped(
57-
_tv: *mut ThreadVars,
57+
_tv: *mut sys::ThreadVars,
5858
_p: *const Packet,
5959
f: *mut Flow,
6060
jb: &mut JsonBuilder,
@@ -66,23 +66,26 @@ fn log_eve_wrapped(
6666
Ok(())
6767
}
6868

69-
fn on_thread_init(tv: *mut ThreadVars) {
70-
SCLogNotice!("rust example thread init callback: thread={:p}", tv);
69+
fn on_thread_init(tv: &mut ThreadVars) {
70+
SCLogNotice!(
71+
"rust example thread init callback: thread={:p}",
72+
tv.as_ptr()
73+
);
7174
}
7275

73-
fn log_flow_init(_tv: *mut ThreadVars, _f: *mut Flow, _p: *const Packet) {
76+
fn log_flow_init(_tv: *mut sys::ThreadVars, _f: *mut Flow, _p: *const Packet) {
7477
SCLogNotice!("rust example flow init callback: flow={:p}", _f);
7578
}
7679

77-
fn log_flow_update(_tv: *mut ThreadVars, _f: *mut Flow, _p: *mut Packet) {
80+
fn log_flow_update(_tv: *mut sys::ThreadVars, _f: *mut Flow, _p: *mut Packet) {
7881
SCLogNotice!(
7982
"rust example flow update callback: flow={:p}, packet={:p}",
8083
_f,
8184
_p
8285
);
8386
}
8487

85-
fn log_flow_finish(_tv: *mut ThreadVars, _f: *mut Flow) {
88+
fn log_flow_finish(_tv: *mut sys::ThreadVars, _f: *mut Flow) {
8689
SCLogNotice!("rust example flow finish callback: flow={:p}", _f);
8790
}
8891

rust/ffi/src/thread.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,9 @@ impl<'a> ThreadVars<'a> {
5252
/// The callback is invoked for every thread being initialized during Suricata
5353
/// startup. It receives the `ThreadVars` for the thread that has just been
5454
/// initialized.
55-
///
56-
/// # Safety
57-
///
58-
/// The callback receives a raw pointer from Suricata. This pointer is only
59-
/// valid for the duration of the callback invocation and must not be stored.
60-
///
61-
/// The callback must not panic.
6255
pub fn register_init_callback<F>(callback: F) -> Result<(), &'static str>
6356
where
64-
F: Fn(*mut sys::ThreadVars) + Send + Sync + 'static,
57+
F: Fn(&mut ThreadVars) + Send + Sync + 'static,
6558
{
6659
let user = Box::into_raw(Box::new(callback)) as *mut c_void;
6760
if unsafe { SCThreadRegisterInitCallback(Some(init_callback_wrapper::<F>), user) } {
@@ -76,8 +69,9 @@ where
7669

7770
unsafe extern "C" fn init_callback_wrapper<F>(tv: *mut sys::ThreadVars, user: *mut c_void)
7871
where
79-
F: Fn(*mut sys::ThreadVars) + Send + Sync + 'static,
72+
F: Fn(&mut ThreadVars) + Send + Sync + 'static,
8073
{
8174
let callback = &*(user as *const F);
82-
callback(tv);
75+
let mut tv = ThreadVars::from_ptr(tv);
76+
callback(&mut tv);
8377
}

0 commit comments

Comments
 (0)