Skip to content

Commit b53e37b

Browse files
committed
fix leak of ffi_closure on panic
Wraps ffi_closure in its own struct to prevent a panic from prep_closure_mut from causing a leak of a ffi_closure object.
1 parent 81c826c commit b53e37b

File tree

2 files changed

+33
-32
lines changed

2 files changed

+33
-32
lines changed

.github/workflows/test.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ jobs:
5151
features:
5252
- "--no-default-features"
5353
- "--features std"
54-
- "--features std,system"
5554
runs-on: windows-latest
5655
name: windows-gnu ${{ matrix.toolchain }} ${{ matrix.features }}
5756
steps:

libffi-rs/src/middle/mod.rs

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
//! aren’t checked. See the [`high`](crate::high) layer for closures
99
//! with type-checked arguments.
1010
11+
use crate::low;
12+
pub use crate::low::{ffi_abi as FfiAbi, ffi_abi_FFI_DEFAULT_ABI, Callback, CallbackMut, CodePtr};
1113
use alloc::boxed::Box;
1214
use core::any::Any;
1315
use core::ffi::c_void;
1416
use core::marker::PhantomData;
15-
16-
use crate::low;
17-
pub use crate::low::{ffi_abi as FfiAbi, ffi_abi_FFI_DEFAULT_ABI, Callback, CallbackMut, CodePtr};
17+
use core::ptr::NonNull;
1818

1919
mod util;
2020

@@ -24,6 +24,17 @@ pub use types::Type;
2424
mod builder;
2525
pub use builder::Builder;
2626

27+
#[derive(Debug)]
28+
pub(crate) struct ClosureAlloc(NonNull<low::ffi_closure>);
29+
30+
impl Drop for ClosureAlloc {
31+
fn drop(&mut self) {
32+
unsafe {
33+
low::closure_free(self.0.as_ptr());
34+
}
35+
}
36+
}
37+
2738
/// Contains an untyped pointer to a function argument.
2839
///
2940
/// When calling a function via a [CIF](Cif), each argument
@@ -50,7 +61,7 @@ impl<'arg> Arg<'arg> {
5061
///
5162
/// This is used to wrap each argument pointer before passing them
5263
/// to [`Cif::call`]. (This is the same as [`Arg::new`]).
53-
pub fn arg<T: ?Sized>(r: &T) -> Arg {
64+
pub fn arg<T: ?Sized>(r: &T) -> Arg<'_> {
5465
Arg::new(r)
5566
}
5667

@@ -277,19 +288,11 @@ impl Cif {
277288
#[derive(Debug)]
278289
pub struct Closure<'a> {
279290
_cif: Box<Cif>,
280-
alloc: *mut low::ffi_closure,
291+
_alloc: ClosureAlloc,
281292
code: CodePtr,
282293
_marker: PhantomData<&'a ()>,
283294
}
284295

285-
impl Drop for Closure<'_> {
286-
fn drop(&mut self) {
287-
unsafe {
288-
low::closure_free(self.alloc);
289-
}
290-
}
291-
}
292-
293296
impl<'a> Closure<'a> {
294297
/// Creates a new closure with immutable userdata.
295298
///
@@ -307,10 +310,11 @@ impl<'a> Closure<'a> {
307310
pub fn new<U, R>(cif: Cif, callback: Callback<U, R>, userdata: &'a U) -> Self {
308311
let cif = Box::new(cif);
309312
let (alloc, code) = low::closure_alloc();
313+
let alloc = ClosureAlloc(NonNull::new(alloc).unwrap());
310314

311315
unsafe {
312316
low::prep_closure(
313-
alloc,
317+
alloc.0.as_ptr(),
314318
cif.as_raw_ptr(),
315319
callback,
316320
userdata as *const U,
@@ -321,7 +325,7 @@ impl<'a> Closure<'a> {
321325

322326
Closure {
323327
_cif: cif,
324-
alloc,
328+
_alloc: alloc,
325329
code,
326330
_marker: PhantomData,
327331
}
@@ -343,15 +347,22 @@ impl<'a> Closure<'a> {
343347
pub fn new_mut<U, R>(cif: Cif, callback: CallbackMut<U, R>, userdata: &'a mut U) -> Self {
344348
let cif = Box::new(cif);
345349
let (alloc, code) = low::closure_alloc();
350+
let alloc = ClosureAlloc(NonNull::new(alloc).unwrap());
346351

347352
unsafe {
348-
low::prep_closure_mut(alloc, cif.as_raw_ptr(), callback, userdata as *mut U, code)
349-
.unwrap();
353+
low::prep_closure_mut(
354+
alloc.0.as_ptr(),
355+
cif.as_raw_ptr(),
356+
callback,
357+
userdata as *mut U,
358+
code,
359+
)
360+
.unwrap();
350361
}
351362

352363
Closure {
353364
_cif: cif,
354-
alloc,
365+
_alloc: alloc,
355366
code,
356367
_marker: PhantomData,
357368
}
@@ -391,20 +402,12 @@ pub type CallbackOnce<U, R> = CallbackMut<Option<U>, R>;
391402
/// which case the userdata will be gone if called again.
392403
#[derive(Debug)]
393404
pub struct ClosureOnce {
394-
alloc: *mut low::ffi_closure,
405+
_alloc: ClosureAlloc,
395406
code: CodePtr,
396407
_cif: Box<Cif>,
397408
_userdata: Box<dyn Any>,
398409
}
399410

400-
impl Drop for ClosureOnce {
401-
fn drop(&mut self) {
402-
unsafe {
403-
low::closure_free(self.alloc);
404-
}
405-
}
406-
}
407-
408411
impl ClosureOnce {
409412
/// Creates a new closure with owned userdata.
410413
///
@@ -423,14 +426,13 @@ impl ClosureOnce {
423426
let _cif = Box::new(cif);
424427
let _userdata = Box::new(Some(userdata)) as Box<dyn Any>;
425428
let (alloc, code) = low::closure_alloc();
426-
427-
assert!(!alloc.is_null(), "closure_alloc: returned null");
429+
let alloc = ClosureAlloc(NonNull::new(alloc).unwrap());
428430

429431
{
430432
let borrow = _userdata.downcast_ref::<Option<U>>().unwrap();
431433
unsafe {
432434
low::prep_closure_mut(
433-
alloc,
435+
alloc.0.as_ptr(),
434436
_cif.as_raw_ptr(),
435437
callback,
436438
borrow as *const _ as *mut _,
@@ -441,7 +443,7 @@ impl ClosureOnce {
441443
}
442444

443445
ClosureOnce {
444-
alloc,
446+
_alloc: alloc,
445447
code,
446448
_cif,
447449
_userdata,

0 commit comments

Comments
 (0)