Skip to content

Commit 91b9f45

Browse files
committed
[Rust] Move ObjectDestructor to own module and add some extra documentation
1 parent f0d2ece commit 91b9f45

File tree

5 files changed

+102
-61
lines changed

5 files changed

+102
-61
lines changed

plugins/warp/src/cache.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,14 @@ pub use type_reference::*;
99

1010
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
1111
use binaryninja::function::Function as BNFunction;
12+
use binaryninja::object_destructor::{register_object_destructor, ObjectDestructor};
1213
use binaryninja::rc::Guard;
1314
use binaryninja::rc::Ref as BNRef;
14-
use binaryninja::ObjectDestructor;
1515
use std::hash::{DefaultHasher, Hash, Hasher};
1616

1717
pub fn register_cache_destructor() {
18-
pub static mut CACHE_DESTRUCTOR: CacheDestructor = CacheDestructor;
19-
#[allow(static_mut_refs)]
20-
// SAFETY: This can be done as the backing data is an opaque ZST.
21-
unsafe {
22-
CACHE_DESTRUCTOR.register()
23-
};
18+
let destructor = register_object_destructor(CacheDestructor);
19+
std::mem::forget(destructor);
2420
}
2521

2622
/// A unique view ID, used for caching.

plugins/warp/src/plugin/debug.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{build_function, cache};
33
use binaryninja::binary_view::BinaryView;
44
use binaryninja::command::{Command, FunctionCommand};
55
use binaryninja::function::Function;
6-
use binaryninja::ObjectDestructor;
6+
use binaryninja::object_destructor::ObjectDestructor;
77

88
pub struct DebugFunction;
99

plugins/workflow_objc/src/metadata/global_state.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use binaryninja::file_metadata::SessionId;
2+
use binaryninja::object_destructor::register_object_destructor;
23
use binaryninja::{
34
binary_view::{BinaryView, BinaryViewBase, BinaryViewExt},
45
file_metadata::FileMetadata,
56
metadata::Metadata,
7+
object_destructor::ObjectDestructor,
68
rc::Ref,
79
settings::{QueryOptions, Settings},
8-
ObjectDestructor,
910
};
1011
use dashmap::DashMap;
1112
use once_cell::sync::Lazy;
@@ -66,8 +67,8 @@ pub struct GlobalState;
6667

6768
impl GlobalState {
6869
pub fn register_cleanup() {
69-
let observer = Box::leak(Box::new(ObjectLifetimeObserver));
70-
observer.register();
70+
let destructor = register_object_destructor(ObjectLifetimeObserver);
71+
std::mem::forget(destructor);
7172
}
7273

7374
fn id(bv: &BinaryView) -> SessionId {

rust/src/lib.rs

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub mod low_level_il;
6565
pub mod main_thread;
6666
pub mod medium_level_il;
6767
pub mod metadata;
68+
pub mod object_destructor;
6869
pub mod platform;
6970
pub mod progress;
7071
pub mod project;
@@ -90,8 +91,6 @@ pub mod websocket;
9091
pub mod worker_thread;
9192
pub mod workflow;
9293

93-
use crate::file_metadata::FileMetadata;
94-
use crate::function::Function;
9594
use crate::progress::{NoProgressCallback, ProgressCallback};
9695
use crate::string::raw_to_string;
9796
use binary_view::BinaryView;
@@ -428,54 +427,6 @@ pub fn memory_info() -> HashMap<String, u64> {
428427
usage
429428
}
430429

431-
/// The trait required for receiving core object destruction callbacks.
432-
pub trait ObjectDestructor: 'static + Sync + Sized {
433-
fn destruct_view(&self, _view: &BinaryView) {}
434-
fn destruct_file_metadata(&self, _metadata: &FileMetadata) {}
435-
fn destruct_function(&self, _func: &Function) {}
436-
437-
unsafe extern "C" fn cb_destruct_binary_view(ctxt: *mut c_void, view: *mut BNBinaryView) {
438-
ffi_wrap!("ObjectDestructor::destruct_view", {
439-
let view_type = &*(ctxt as *mut Self);
440-
let view = BinaryView { handle: view };
441-
view_type.destruct_view(&view);
442-
})
443-
}
444-
445-
unsafe extern "C" fn cb_destruct_file_metadata(ctxt: *mut c_void, file: *mut BNFileMetadata) {
446-
ffi_wrap!("ObjectDestructor::destruct_file_metadata", {
447-
let view_type = &*(ctxt as *mut Self);
448-
let file = FileMetadata::from_raw(file);
449-
view_type.destruct_file_metadata(&file);
450-
})
451-
}
452-
453-
unsafe extern "C" fn cb_destruct_function(ctxt: *mut c_void, func: *mut BNFunction) {
454-
ffi_wrap!("ObjectDestructor::destruct_function", {
455-
let view_type = &*(ctxt as *mut Self);
456-
let func = Function { handle: func };
457-
view_type.destruct_function(&func);
458-
})
459-
}
460-
461-
unsafe fn as_callbacks(&'static mut self) -> BNObjectDestructionCallbacks {
462-
BNObjectDestructionCallbacks {
463-
context: std::mem::transmute(&self),
464-
destructBinaryView: Some(Self::cb_destruct_binary_view),
465-
destructFileMetadata: Some(Self::cb_destruct_file_metadata),
466-
destructFunction: Some(Self::cb_destruct_function),
467-
}
468-
}
469-
470-
fn register(&'static mut self) {
471-
unsafe { BNRegisterObjectDestructionCallbacks(&mut self.as_callbacks()) };
472-
}
473-
474-
fn unregister(&'static mut self) {
475-
unsafe { BNUnregisterObjectDestructionCallbacks(&mut self.as_callbacks()) };
476-
}
477-
}
478-
479430
pub fn version() -> String {
480431
unsafe { BnString::into_string(BNGetVersionString()) }
481432
}

rust/src/object_destructor.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! Register callbacks for when core objects like [`BinaryView`]s or [`Function`]s are destroyed.
2+
3+
use crate::binary_view::BinaryView;
4+
use crate::file_metadata::FileMetadata;
5+
use crate::function::Function;
6+
use binaryninjacore_sys::*;
7+
use std::ffi::c_void;
8+
9+
/// Registers a destructor which will be called when certain core objects are about to be destroyed.
10+
///
11+
/// Returns a handle to the registered destructor. The destructor will be unregistered when the handle is dropped.
12+
///
13+
/// To keep the destructor alive forever, move the [`ObjectDestructorHandle`] into [`std::mem::ManuallyDrop`].
14+
#[must_use = "The destructor will be unregistered when the handle is dropped"]
15+
pub fn register_object_destructor<'a, D: ObjectDestructor>(
16+
destructor: D,
17+
) -> ObjectDestructorHandle<'a, D> {
18+
let destructor = Box::leak(Box::new(destructor));
19+
let callbacks = BNObjectDestructionCallbacks {
20+
context: destructor as *mut _ as *mut c_void,
21+
destructBinaryView: Some(cb_destruct_binary_view::<D>),
22+
destructFileMetadata: Some(cb_destruct_file_metadata::<D>),
23+
destructFunction: Some(cb_destruct_function::<D>),
24+
};
25+
let mut handle = ObjectDestructorHandle {
26+
callbacks,
27+
_life: std::marker::PhantomData,
28+
};
29+
unsafe { BNRegisterObjectDestructionCallbacks(&mut handle.callbacks) };
30+
handle
31+
}
32+
33+
/// The handle for the [`ObjectDestructor`].
34+
///
35+
/// Once this handle is dropped, the destructor will be unregistered and the associated resources will be cleaned up.
36+
pub struct ObjectDestructorHandle<'a, D: ObjectDestructor> {
37+
callbacks: BNObjectDestructionCallbacks,
38+
_life: std::marker::PhantomData<&'a D>,
39+
}
40+
41+
impl<D: ObjectDestructor> Drop for ObjectDestructorHandle<'_, D> {
42+
fn drop(&mut self) {
43+
unsafe { BNUnregisterObjectDestructionCallbacks(&mut self.callbacks) };
44+
let _ = unsafe { Box::from_raw(self.callbacks.context as *mut D) };
45+
}
46+
}
47+
48+
/// The trait required for receiving core object destruction callbacks.
49+
///
50+
/// This is useful for cleaning up resources which are associated with a given core object.
51+
pub trait ObjectDestructor: 'static + Sync + Sized {
52+
/// Called when a [`BinaryView`] is about to be destroyed.
53+
fn destruct_view(&self, _view: &BinaryView) {}
54+
55+
/// Called when a [`FileMetadata`] is about to be destroyed.
56+
fn destruct_file_metadata(&self, _metadata: &FileMetadata) {}
57+
58+
/// Called when a [`Function`] is about to be destroyed.
59+
fn destruct_function(&self, _func: &Function) {}
60+
}
61+
62+
unsafe extern "C" fn cb_destruct_binary_view<D: ObjectDestructor>(
63+
ctxt: *mut c_void,
64+
view: *mut BNBinaryView,
65+
) {
66+
ffi_wrap!("ObjectDestructor::destruct_view", {
67+
let destructor = &*(ctxt as *mut D);
68+
let view = BinaryView { handle: view };
69+
destructor.destruct_view(&view);
70+
})
71+
}
72+
73+
unsafe extern "C" fn cb_destruct_file_metadata<D: ObjectDestructor>(
74+
ctxt: *mut c_void,
75+
file: *mut BNFileMetadata,
76+
) {
77+
ffi_wrap!("ObjectDestructor::destruct_file_metadata", {
78+
let destructor = &*(ctxt as *mut D);
79+
let file = FileMetadata::from_raw(file);
80+
destructor.destruct_file_metadata(&file);
81+
})
82+
}
83+
84+
unsafe extern "C" fn cb_destruct_function<D: ObjectDestructor>(
85+
ctxt: *mut c_void,
86+
func: *mut BNFunction,
87+
) {
88+
ffi_wrap!("ObjectDestructor::destruct_function", {
89+
let destructor = &*(ctxt as *mut D);
90+
let func = Function { handle: func };
91+
destructor.destruct_function(&func);
92+
})
93+
}

0 commit comments

Comments
 (0)