#[no_mangle]
pub unsafe extern "C" fn stretch_node_compute_layout(
stretch: *mut c_void,
node: *mut c_void,
width: f32,
height: f32,
create_layout: fn(*const f32) -> *mut c_void,
) -> *mut c_void {
let mut stretch = Box::from_raw(stretch as *mut Stretch);
let node = Box::from_raw(node as *mut Node);
stretch
.compute_layout(
*node,
Size {
width: if f32::is_nan(width) { Number::Undefined } else { Number::Defined(width) },
height: if f32::is_nan(height) { Number::Undefined } else { Number::Defined(height) },
},
)
.unwrap();
let mut output = vec![];
copy_output(&stretch, *node, &mut output);
Box::leak(stretch);
Box::leak(node);
create_layout(output.as_ptr())
}
The unwinding of stretch.compute_layout will introduce double free due to dropping stretch and node in the unwinding path. With the appearance of this question, we noticed that this kind of from_raw usage is not strong enough for FFI functions😨.
The leak should take forward to avoid the automated deallocation towards objects generating by from_raw. We found std::mem::ManuallyDrop is a good wrapper for us to avoid the drop as well as making the variable act like the smart pointer.
The fixed code we listed below. And this refinement is zero-cost.
#[no_mangle]
pub unsafe extern "C" fn stretch_node_compute_layout(
stretch: *mut c_void,
node: *mut c_void,
width: f32,
height: f32,
create_layout: fn(*const f32) -> *mut c_void,
) -> *mut c_void {
let mut stretch = mem::ManuallyDrop::new(Box::from_raw(stretch as *mut Stretch));
let node = mem::ManuallyDrop::new(Box::from_raw(node as *mut Node));
stretch
.compute_layout(
*node,
Size {
width: if f32::is_nan(width) { Number::Undefined } else { Number::Defined(width) },
height: if f32::is_nan(height) { Number::Undefined } else { Number::Defined(height) },
},
)
.unwrap();
let mut output = vec![];
copy_output(&stretch, *node, &mut output);
create_layout(output.as_ptr())
}
We think all the usage (involving 24 functions) of from_raw in bindings for Swift and Kotlin should be changed by wrapping with ManuallyDrop to avoid double free incurred by unwinding 😊.
The unwinding of
stretch.compute_layoutwill introduce double free due to droppingstretchandnodein the unwinding path. With the appearance of this question, we noticed that this kind offrom_rawusage is not strong enough for FFI functions😨.The
leakshould take forward to avoid the automated deallocation towards objects generating byfrom_raw. We foundstd::mem::ManuallyDropis a good wrapper for us to avoid the drop as well as making the variable act like the smart pointer.The fixed code we listed below. And this refinement is zero-cost.
We think all the usage (involving 24 functions) of
from_rawin bindings for Swift and Kotlin should be changed by wrapping withManuallyDropto avoid double free incurred by unwinding 😊.