Skip to content

Commit 8817116

Browse files
committed
Merge branch 'fix-vec-leak' of github.com:rbran/binaryninja-api into dev
2 parents 44b0519 + ee6abdd commit 8817116

File tree

2 files changed

+55
-68
lines changed

2 files changed

+55
-68
lines changed

rust/src/architecture.rs

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,10 +1162,11 @@ impl Architecture for CoreArchitecture {
11621162
&mut result as *mut _,
11631163
&mut count as *mut _,
11641164
) {
1165-
let vec = Vec::<BNInstructionTextToken>::from_raw_parts(result, count, count)
1165+
let vec = slice::from_raw_parts(result, count)
11661166
.iter()
1167-
.map(|x| InstructionTextToken::from_raw(x))
1167+
.map(|x| InstructionTextToken::from_raw(x).to_owned())
11681168
.collect();
1169+
BNFreeInstructionText(result, count);
11691170
Some((consumed, vec))
11701171
} else {
11711172
None
@@ -1810,27 +1811,25 @@ where
18101811
let data = unsafe { slice::from_raw_parts(data, *len) };
18111812
let result = unsafe { &mut *result };
18121813

1813-
match custom_arch.instruction_text(data, addr) {
1814-
Some((res_size, mut res_tokens)) => {
1815-
unsafe {
1816-
// TODO: Can't use into_raw_parts as it's unstable so we do this instead...
1817-
let r_ptr = res_tokens.as_mut_ptr();
1818-
let r_count = res_tokens.len();
1819-
mem::forget(res_tokens);
1820-
1821-
*result = &mut (*r_ptr).0;
1822-
*count = r_count;
1823-
*len = res_size;
1824-
}
1825-
true
1826-
}
1827-
None => false,
1814+
let Some((res_size, res_tokens)) = custom_arch.instruction_text(data, addr) else {
1815+
return false;
1816+
};
1817+
1818+
let res_tokens: Box<[_]> = res_tokens.into_boxed_slice();
1819+
unsafe {
1820+
let res_tokens = Box::leak(res_tokens);
1821+
let r_ptr = res_tokens.as_mut_ptr();
1822+
let r_count = res_tokens.len();
1823+
1824+
*result = &mut (*r_ptr).0;
1825+
*count = r_count;
1826+
*len = res_size;
18281827
}
1828+
true
18291829
}
18301830

18311831
extern "C" fn cb_free_instruction_text(tokens: *mut BNInstructionTextToken, count: usize) {
1832-
let _tokens =
1833-
unsafe { Vec::from_raw_parts(tokens as *mut InstructionTextToken, count, count) };
1832+
let _tokens = unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(tokens, count)) };
18341833
}
18351834

18361835
extern "C" fn cb_instruction_llil<A>(
@@ -1930,15 +1929,7 @@ where
19301929
if len == 0 {
19311930
ptr::null_mut()
19321931
} else {
1933-
let mut res = Vec::with_capacity(len + 1);
1934-
1935-
res.push(len as u32);
1936-
1937-
for i in items {
1938-
res.push(i);
1939-
}
1940-
1941-
assert!(res.len() == len + 1);
1932+
let mut res: Box<[_]> = [len as u32].into_iter().chain(items).collect();
19421933

19431934
let raw = res.as_mut_ptr();
19441935
mem::forget(res);
@@ -2279,7 +2270,8 @@ where
22792270
unsafe {
22802271
let actual_start = regs.offset(-1);
22812272
let len = *actual_start + 1;
2282-
let _regs = Vec::from_raw_parts(actual_start, len as usize, len as usize);
2273+
let regs_ptr = ptr::slice_from_raw_parts_mut(actual_start, len.try_into().unwrap());
2274+
let _regs = Box::from_raw(regs_ptr);
22832275
}
22842276
}
22852277

@@ -2419,28 +2411,25 @@ where
24192411
{
24202412
let custom_arch = unsafe { &*(ctxt as *mut A) };
24212413

2422-
if let Some(intrinsic) = custom_arch.intrinsic_from_id(intrinsic) {
2423-
let inputs = intrinsic.inputs();
2424-
let mut res = Vec::with_capacity(inputs.len());
2425-
for input in inputs {
2426-
res.push(unsafe { Ref::into_raw(input) }.into_raw());
2427-
}
2428-
2429-
unsafe {
2430-
*count = res.len();
2431-
if res.is_empty() {
2432-
ptr::null_mut()
2433-
} else {
2434-
let raw = res.as_mut_ptr();
2435-
mem::forget(res);
2436-
raw
2437-
}
2438-
}
2439-
} else {
2414+
let Some(intrinsic) = custom_arch.intrinsic_from_id(intrinsic) else {
24402415
unsafe {
24412416
*count = 0;
24422417
}
2443-
ptr::null_mut()
2418+
return ptr::null_mut();
2419+
};
2420+
2421+
let inputs = intrinsic.inputs();
2422+
let mut res: Box<[_]> = inputs.into_iter().map(|input| input.into_raw()).collect();
2423+
2424+
unsafe {
2425+
*count = res.len();
2426+
if res.is_empty() {
2427+
ptr::null_mut()
2428+
} else {
2429+
let raw = res.as_mut_ptr();
2430+
mem::forget(res);
2431+
raw
2432+
}
24442433
}
24452434
}
24462435

@@ -2452,8 +2441,8 @@ where
24522441

24532442
if !nt.is_null() {
24542443
unsafe {
2455-
let list = Vec::from_raw_parts(nt, count, count);
2456-
for nt in list {
2444+
let name_and_types = Box::from_raw(ptr::slice_from_raw_parts_mut(nt, count));
2445+
for nt in name_and_types.into_iter() {
24572446
BnString::from_raw(nt.name);
24582447
}
24592448
}
@@ -2472,10 +2461,7 @@ where
24722461

24732462
if let Some(intrinsic) = custom_arch.intrinsic_from_id(intrinsic) {
24742463
let inputs = intrinsic.outputs();
2475-
let mut res = Vec::with_capacity(inputs.len());
2476-
for input in inputs.iter() {
2477-
res.push(input.as_ref().into());
2478-
}
2464+
let mut res: Box<[_]> = inputs.iter().map(|input| input.as_ref().into()).collect();
24792465

24802466
unsafe {
24812467
*count = res.len();
@@ -2504,9 +2490,7 @@ where
25042490
{
25052491
let _custom_arch = unsafe { &*(ctxt as *mut A) };
25062492
if !tl.is_null() {
2507-
unsafe {
2508-
let _list = Vec::from_raw_parts(tl, count, count);
2509-
}
2493+
let _type_list = unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(tl, count)) };
25102494
}
25112495
}
25122496

rust/src/disassembly.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub type InstructionTextTokenContext = BNInstructionTextTokenContext;
7373
// IndirectImportToken = 69,
7474
// ExternalSymbolToken = 70,
7575

76-
#[repr(C)]
76+
#[repr(transparent)]
7777
pub struct InstructionTextToken(pub(crate) BNInstructionTextToken);
7878

7979
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -99,8 +99,8 @@ pub enum InstructionTextTokenContents {
9999
}
100100

101101
impl InstructionTextToken {
102-
pub(crate) unsafe fn from_raw(raw: &BNInstructionTextToken) -> Self {
103-
Self(*raw)
102+
pub(crate) unsafe fn from_raw(raw: &BNInstructionTextToken) -> &Self {
103+
mem::transmute(raw)
104104
}
105105

106106
pub fn new(text: &str, contents: InstructionTextTokenContents) -> Self {
@@ -254,13 +254,16 @@ impl Clone for InstructionTextToken {
254254
}
255255
}
256256

257-
// TODO : There is almost certainly a memory leak here - in the case where
258-
// `impl CoreOwnedArrayProvider for InstructionTextToken` doesn't get triggered
259-
// impl Drop for InstructionTextToken {
260-
// fn drop(&mut self) {
261-
// let _owned = unsafe { BnString::from_raw(self.0.text) };
262-
// }
263-
// }
257+
impl Drop for InstructionTextToken {
258+
fn drop(&mut self) {
259+
if !self.0.text.is_null() {
260+
let _owned = unsafe { BnString::from_raw(self.0.text) };
261+
}
262+
if !self.0.typeNames.is_null() && self.0.namesCount != 0 {
263+
unsafe { BNFreeStringList(self.0.typeNames, self.0.namesCount) }
264+
}
265+
}
266+
}
264267

265268
pub struct DisassemblyTextLine(pub(crate) BNDisassemblyTextLine);
266269

@@ -290,7 +293,7 @@ impl DisassemblyTextLine {
290293
unsafe {
291294
std::slice::from_raw_parts::<BNInstructionTextToken>(self.0.tokens, self.0.count)
292295
.iter()
293-
.map(|&x| InstructionTextToken::from_raw(&x))
296+
.map(|x| InstructionTextToken::from_raw(x).clone())
294297
.collect()
295298
}
296299
}

0 commit comments

Comments
 (0)