Skip to content

Commit 82cee46

Browse files
committed
[Core] Add optional callback for when the type archive closes for BNTypeArchiveNotification
Update the rust bindings accordingly
1 parent 9f8e6c6 commit 82cee46

2 files changed

Lines changed: 59 additions & 31 deletions

File tree

binaryninjacore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,6 +3561,7 @@ extern "C"
35613561
void (*typeUpdated)(void* ctxt, BNTypeArchive* archive, const char* id, BNType* oldDefinition, BNType* newDefinition);
35623562
void (*typeRenamed)(void* ctxt, BNTypeArchive* archive, const char* id, const BNQualifiedName* oldName, const BNQualifiedName* newName);
35633563
void (*typeDeleted)(void* ctxt, BNTypeArchive* archive, const char* id, BNType* definition);
3564+
void (*closed)(void* ctxt, BNTypeArchive* archive);
35643565
} BNTypeArchiveNotification;
35653566

35663567
BN_ENUM(uint8_t, BNTypeContainerType)

rust/src/types/archive.rs

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -616,36 +616,40 @@ impl TypeArchive {
616616
}
617617

618618
/// Register a notification listener
619-
pub fn register_notification_callback<T: TypeArchiveNotificationCallback>(
619+
#[must_use]
620+
pub fn register_notification_callback<'a, T: TypeArchiveNotificationCallback + 'a>(
620621
&self,
621622
callback: T,
622-
) -> TypeArchiveCallbackHandle<T> {
623+
) -> TypeArchiveCallbackHandle<'a, T> {
623624
// SAFETY free on [TypeArchiveCallbackHandle::Drop]
624625
let callback = Box::leak(Box::new(callback));
625-
let mut notification = BNTypeArchiveNotification {
626+
let notification = BNTypeArchiveNotification {
626627
context: callback as *mut T as *mut c_void,
627628
typeAdded: Some(cb_type_added::<T>),
628629
typeUpdated: Some(cb_type_updated::<T>),
629630
typeRenamed: Some(cb_type_renamed::<T>),
630631
typeDeleted: Some(cb_type_deleted::<T>),
632+
closed: Some(cb_type_archive_closed::<T>),
631633
};
632-
unsafe { BNRegisterTypeArchiveNotification(self.handle.as_ptr(), &mut notification) }
634+
let mut boxed_notification = Box::new(notification);
635+
unsafe {
636+
BNRegisterTypeArchiveNotification(self.handle.as_ptr(), boxed_notification.as_mut())
637+
}
633638
TypeArchiveCallbackHandle {
634-
callback,
635639
type_archive: self.to_owned(),
640+
handle: boxed_notification,
641+
_lifetime: Default::default(),
636642
}
637643
}
638644

639-
// NOTE NotificationClosure is left private, there is no need for the user
640-
// to know or use it.
641-
#[allow(private_interfaces)]
642-
pub fn register_notification_closure<A, U, R, D>(
645+
#[must_use]
646+
pub fn register_notification_closure<'a, A, U, R, D>(
643647
&self,
644648
type_added: A,
645649
type_updated: U,
646650
type_renamed: R,
647651
type_deleted: D,
648-
) -> TypeArchiveCallbackHandle<NotificationClosure<A, U, R, D>>
652+
) -> TypeArchiveCallbackHandle<'a, NotificationClosure<A, U, R, D>>
649653
where
650654
A: FnMut(&TypeArchive, &str, &Type),
651655
U: FnMut(&TypeArchive, &str, &Type, &Type),
@@ -661,7 +665,9 @@ impl TypeArchive {
661665
}
662666

663667
/// Close a type archive, disconnecting it from any active views and closing
664-
/// any open file handles
668+
/// any open file handles.
669+
///
670+
/// This will signal all registered notification callbacks with [`TypeArchiveNotificationCallback::closed`].
665671
pub fn close(&self) {
666672
unsafe { BNCloseTypeArchive(self.handle.as_ptr()) }
667673
}
@@ -874,29 +880,35 @@ unsafe impl CoreArrayProviderInner for TypeArchive {
874880
}
875881
}
876882

877-
pub struct TypeArchiveCallbackHandle<T: TypeArchiveNotificationCallback> {
878-
callback: *mut T,
883+
pub struct TypeArchiveCallbackHandle<'a, T: TypeArchiveNotificationCallback>
884+
where
885+
T: 'a,
886+
{
879887
type_archive: Ref<TypeArchive>,
888+
handle: Box<BNTypeArchiveNotification>,
889+
_lifetime: std::marker::PhantomData<&'a T>,
880890
}
881891

882-
impl<T: TypeArchiveNotificationCallback> Drop for TypeArchiveCallbackHandle<T> {
892+
impl<T: TypeArchiveNotificationCallback> TypeArchiveCallbackHandle<'_, T> {
893+
unsafe fn unregister_for_archive(&mut self) {
894+
BNUnregisterTypeArchiveNotification(self.type_archive.handle.as_ptr(), self.handle.as_mut())
895+
}
896+
897+
unsafe fn extract_context(&mut self) -> Box<T> {
898+
Box::from_raw(self.handle.context as *mut T)
899+
}
900+
901+
pub fn unregister(mut self) -> T {
902+
unsafe { self.unregister_for_archive() };
903+
unsafe { *self.extract_context() }
904+
}
905+
}
906+
907+
impl<T: TypeArchiveNotificationCallback> Drop for TypeArchiveCallbackHandle<'_, T> {
883908
fn drop(&mut self) {
884-
let mut notification = BNTypeArchiveNotification {
885-
context: self.callback as *mut c_void,
886-
typeAdded: Some(cb_type_added::<T>),
887-
typeUpdated: Some(cb_type_updated::<T>),
888-
typeRenamed: Some(cb_type_renamed::<T>),
889-
typeDeleted: Some(cb_type_deleted::<T>),
890-
};
891-
// unregister the notification callback
892-
unsafe {
893-
BNUnregisterTypeArchiveNotification(
894-
self.type_archive.handle.as_ptr(),
895-
&mut notification,
896-
)
897-
}
898-
// free the context created at [TypeArchive::register_notification_callback]
899-
drop(unsafe { Box::from_raw(self.callback) });
909+
unsafe { self.unregister_for_archive() };
910+
// drop context, avoid memory leak
911+
let _ctxt = unsafe { self.extract_context() };
900912
}
901913
}
902914

@@ -944,9 +956,14 @@ pub trait TypeArchiveNotificationCallback {
944956
/// * `id` - Id of type deleted
945957
/// * `definition` - Definition of type deleted
946958
fn type_deleted(&mut self, _archive: &TypeArchive, _id: &str, _definition: &Type) {}
959+
960+
/// Called when the associated type archive is closed.
961+
///
962+
/// Useful to free up data in this context associated with the type archive.
963+
fn closed(&mut self, _archive: &TypeArchive) {}
947964
}
948965

949-
struct NotificationClosure<A, U, R, D>
966+
pub struct NotificationClosure<A, U, R, D>
950967
where
951968
A: FnMut(&TypeArchive, &str, &Type),
952969
U: FnMut(&TypeArchive, &str, &Type, &Type),
@@ -1068,6 +1085,16 @@ unsafe extern "C" fn cb_type_deleted<T: TypeArchiveNotificationCallback>(
10681085
)
10691086
}
10701087

1088+
unsafe extern "C" fn cb_type_archive_closed<T: TypeArchiveNotificationCallback>(
1089+
ctxt: *mut ::std::os::raw::c_void,
1090+
archive: *mut BNTypeArchive,
1091+
) {
1092+
let ctxt: &mut T = &mut *(ctxt as *mut T);
1093+
// `archive` is owned by the caller.
1094+
let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) };
1095+
ctxt.closed(&archive)
1096+
}
1097+
10711098
#[repr(transparent)]
10721099
pub struct TypeArchiveMergeConflict {
10731100
handle: NonNull<BNTypeArchiveMergeConflict>,

0 commit comments

Comments
 (0)