Skip to content

Commit 3148e2d

Browse files
lukbukkitemesare
authored andcommitted
Models CoreDataRenderer after CoreTypePrinter to prevent crashes
The previous approach of reference counting did lead to crashes as the renderer was freed after registration :/
1 parent 8d594bc commit 3148e2d

File tree

1 file changed

+52
-66
lines changed

1 file changed

+52
-66
lines changed

rust/src/data_renderer.rs

Lines changed: 52 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
use core::ffi;
2-
2+
use ffi::c_void;
3+
use std::ptr::NonNull;
4+
use log::debug;
35
use binaryninjacore_sys::*;
46

57
use crate::binary_view::BinaryView;
68
use crate::disassembly::{DisassemblyTextLine, InstructionTextToken};
7-
use crate::rc::{Ref, RefCountable};
89
use crate::types::Type;
910

1011
// NOTE the type_ inside the context can be both owned or borrowed, because
1112
// this type only exist as a reference and is never created by itself (AKA
1213
// don't have a *from_raw function, it don't need to worry about drop it.
1314
#[repr(transparent)]
14-
pub struct TypeContext(BNTypeContext);
15+
pub struct TypeContext {
16+
handle: BNTypeContext
17+
}
1518

1619
impl TypeContext {
1720
pub fn type_(&self) -> &Type {
21+
// debug!("TypeContext type_");
1822
// SAFETY Type and `*mut BNType` are transparent
19-
unsafe { core::mem::transmute::<&*mut BNType, &Type>(&self.0.type_) }
23+
unsafe { core::mem::transmute::<&*mut BNType, &Type>(&self.handle.type_) }
2024
}
2125

2226
pub fn offset(&self) -> usize {
23-
self.0.offset
27+
// debug!("TypeContext offset");
28+
self.handle.offset
2429
}
2530
}
2631

@@ -46,18 +51,20 @@ pub trait CustomDataRenderer: Sized + Sync + Send + 'static {
4651
}
4752

4853
trait CustomDataRendererFFI: CustomDataRenderer {
49-
unsafe extern "C" fn free_object_ffi(ctxt: *mut ffi::c_void) {
54+
unsafe extern "C" fn free_object_ffi(ctxt: *mut c_void) {
55+
// debug!("free_object_ffi");
5056
drop(Box::from_raw(ctxt as *mut Self))
5157
}
5258

5359
unsafe extern "C" fn is_valid_for_data_ffi(
54-
ctxt: *mut ffi::c_void,
60+
ctxt: *mut c_void,
5561
view: *mut BNBinaryView,
5662
addr: u64,
5763
type_: *mut BNType,
5864
type_ctx: *mut BNTypeContext,
5965
ctx_count: usize,
6066
) -> bool {
67+
// debug!("is_valid_for_data_ffi");
6168
let ctxt = ctxt as *mut Self;
6269
// SAFETY BNTypeContext and TypeContext are transparent
6370
let types = core::slice::from_raw_parts(type_ctx as *mut TypeContext, ctx_count);
@@ -70,7 +77,7 @@ trait CustomDataRendererFFI: CustomDataRenderer {
7077
}
7178

7279
unsafe extern "C" fn get_lines_for_data_ffi(
73-
ctxt: *mut ffi::c_void,
80+
ctxt: *mut c_void,
7481
view: *mut BNBinaryView,
7582
addr: u64,
7683
type_: *mut BNType,
@@ -82,6 +89,7 @@ trait CustomDataRendererFFI: CustomDataRenderer {
8289
ctx_count: usize,
8390
language: *const ffi::c_char,
8491
) -> *mut BNDisassemblyTextLine {
92+
// debug!("get_lines_for_data_ffi");
8593
let ctxt = ctxt as *mut Self;
8694
// SAFETY BNTypeContext and TypeContext are transparent
8795
let types = core::slice::from_raw_parts(type_ctx as *mut TypeContext, ctx_count);
@@ -104,10 +112,11 @@ trait CustomDataRendererFFI: CustomDataRenderer {
104112
}
105113

106114
unsafe extern "C" fn free_lines_ffi(
107-
_ctx: *mut ffi::c_void,
115+
_ctx: *mut c_void,
108116
lines: *mut BNDisassemblyTextLine,
109117
count: usize,
110118
) {
119+
// debug!("free_lines_ffi");
111120
let lines = Box::from_raw(core::slice::from_raw_parts_mut(lines, count));
112121
drop(
113122
lines
@@ -120,78 +129,55 @@ trait CustomDataRendererFFI: CustomDataRenderer {
120129

121130
impl<C: CustomDataRenderer> CustomDataRendererFFI for C {}
122131

123-
pub struct CoreDataRenderer(*mut BNDataRenderer);
124-
125-
impl CoreDataRenderer {
126-
pub(crate) unsafe fn ref_from_raw(raw: *mut BNDataRenderer) -> Ref<Self> {
127-
Ref::new(Self(raw))
128-
}
129-
pub(crate) fn as_raw(&self) -> *mut BNDataRenderer {
130-
self.0
131-
}
132+
pub struct CoreDataRenderer {
133+
pub(crate) handle: NonNull<BNDataRenderer>,
132134
}
133135

134-
unsafe impl RefCountable for CoreDataRenderer {
135-
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
136-
Self::ref_from_raw(BNNewDataRendererReference(handle.0))
137-
}
138-
139-
unsafe fn dec_ref(handle: &Self) {
140-
BNFreeDataRenderer(handle.0);
141-
}
142-
}
143-
144-
impl ToOwned for CoreDataRenderer {
145-
type Owned = Ref<Self>;
146-
147-
fn to_owned(&self) -> Self::Owned {
148-
unsafe { <Self as RefCountable>::inc_ref(self) }
136+
impl CoreDataRenderer {
137+
pub(crate) unsafe fn from_raw(handle: NonNull<BNDataRenderer>) -> CoreDataRenderer {
138+
Self { handle }
149139
}
150140
}
151141

152-
fn create_custom_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> {
153-
let custom = Box::leak(Box::new(custom));
142+
fn create_custom_data_renderer<T: CustomDataRenderer>(renderer: T) -> (&'static mut T, CoreDataRenderer) {
143+
let renderer = Box::leak(Box::new(renderer));
154144
let mut callbacks = BNCustomDataRenderer {
155-
context: custom as *mut C as *mut ffi::c_void,
156-
freeObject: Some(<C as CustomDataRendererFFI>::free_object_ffi),
157-
isValidForData: Some(<C as CustomDataRendererFFI>::is_valid_for_data_ffi),
158-
getLinesForData: Some(<C as CustomDataRendererFFI>::get_lines_for_data_ffi),
159-
freeLines: Some(<C as CustomDataRendererFFI>::free_lines_ffi),
145+
context: renderer as *mut _ as *mut c_void,
146+
freeObject: Some(<T as CustomDataRendererFFI>::free_object_ffi),
147+
isValidForData: Some(<T as CustomDataRendererFFI>::is_valid_for_data_ffi),
148+
getLinesForData: Some(<T as CustomDataRendererFFI>::get_lines_for_data_ffi),
149+
freeLines: Some(<T as CustomDataRendererFFI>::free_lines_ffi),
160150
};
161-
unsafe { CoreDataRenderer::ref_from_raw(BNCreateDataRenderer(&mut callbacks)) }
151+
let result = unsafe { BNCreateDataRenderer(&mut callbacks) };
152+
let core = unsafe { CoreDataRenderer::from_raw(NonNull::new(result).unwrap()) };
153+
(renderer, core)
162154
}
163155

164-
pub fn register_generic_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> {
165-
let renderer = create_custom_data_renderer(custom);
166-
register_generic_renderer(&renderer);
167-
renderer
156+
pub fn register_generic_data_renderer<T: CustomDataRenderer>(custom: T) -> (&'static mut T, CoreDataRenderer) {
157+
let (renderer, core) = create_custom_data_renderer(custom);
158+
// debug!("register_generic_data_renderer: core={:?}", core.handle);
159+
let container = DataRendererContainer::get();
160+
unsafe { BNRegisterGenericDataRenderer(container.handle, core.handle.as_ptr()) }
161+
(renderer, core)
168162
}
169163

170-
pub fn register_specific_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> {
171-
let renderer = create_custom_data_renderer(custom);
172-
register_specific_renderer(&renderer);
173-
renderer
164+
pub fn register_specific_data_renderer<C: CustomDataRenderer>(custom: C) -> (&'static mut C, CoreDataRenderer) {
165+
let (renderer, core) = create_custom_data_renderer(custom);
166+
// debug!("register_specific_data_renderer: core={:?}", core.handle);
167+
let container = DataRendererContainer::get();
168+
unsafe { BNRegisterTypeSpecificDataRenderer(container.handle, core.handle.as_ptr()) }
169+
(renderer, core)
174170
}
175171

176172
#[derive(Clone, Copy)]
177-
struct DataRendererContainer(*mut BNDataRendererContainer);
173+
struct DataRendererContainer {
174+
pub(crate) handle: *mut BNDataRendererContainer
175+
}
178176

179177
impl DataRendererContainer {
180-
pub(crate) fn as_raw(&self) -> *mut BNDataRendererContainer {
181-
self.0
182-
}
183-
184178
pub fn get() -> Self {
185-
Self(unsafe { BNGetDataRendererContainer() })
179+
Self {
180+
handle: unsafe { BNGetDataRendererContainer() }
181+
}
186182
}
187-
}
188-
189-
fn register_generic_renderer(renderer: &CoreDataRenderer) {
190-
let container = DataRendererContainer::get();
191-
unsafe { BNRegisterGenericDataRenderer(container.as_raw(), renderer.as_raw()) }
192-
}
193-
194-
fn register_specific_renderer(renderer: &CoreDataRenderer) {
195-
let container = DataRendererContainer::get();
196-
unsafe { BNRegisterTypeSpecificDataRenderer(container.as_raw(), renderer.as_raw()) }
197-
}
183+
}

0 commit comments

Comments
 (0)