Skip to content

Commit 8a9de2d

Browse files
committed
fix(ffi): use ManuallyDrop to leak memory for Uiua code to free
1 parent a9be18e commit 8a9de2d

File tree

1 file changed

+74
-115
lines changed

1 file changed

+74
-115
lines changed

src/ffi.rs

Lines changed: 74 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ pub(crate) use enabled::*;
222222
mod enabled {
223223
use std::{
224224
any::{type_name, Any},
225-
mem::{forget, take, transmute},
225+
mem::{forget, take, transmute, ManuallyDrop},
226226
ptr, slice,
227227
};
228228

@@ -639,10 +639,10 @@ mod enabled {
639639

640640
type ListStorage<T> = (*mut T, Box<[T]>);
641641

642-
#[derive(Default)]
642+
#[derive(Default, Debug)]
643643
struct FfiBindings {
644-
arg_data: Vec<Box<dyn Any>>,
645-
other_data: Vec<Box<dyn Any>>,
644+
arg_data: Vec<ManuallyDrop<Box<dyn Any>>>,
645+
other_data: Vec<ManuallyDrop<Box<dyn Any>>>,
646646
args: Vec<Arg>,
647647
}
648648

@@ -652,118 +652,79 @@ mod enabled {
652652
self.args.pop().unwrap();
653653
self.other_data.push(self.arg_data.pop().unwrap());
654654
}
655-
fn alloc_and_push_ptr_to<T: Any + Copy + std::fmt::Debug>(&mut self, arg: T) -> *mut () {
656-
let mut bx = Box::<T>::new(arg);
657-
let ptr: *mut T = &mut *bx;
655+
fn alloc_and_push_ptr_to<T: Any>(&mut self, arg: T) -> *mut () {
656+
let mut arg = Box::new(arg);
657+
let ptr: *mut T = arg.as_mut();
658658
dbgln!(" create *mut {}: {ptr:p}", type_name::<T>());
659-
self.arg_data.push(Box::new((ptr, bx)));
660-
self.args.push(Arg::new(
661-
&(self.arg_data.last().unwrap())
662-
.downcast_ref::<(*mut T, Box<T>)>()
663-
.unwrap_or_else(|| {
664-
panic!(
665-
"Value wasn't expected type {}",
666-
type_name::<(*mut T, Box<T>)>()
667-
)
668-
})
669-
.0,
670-
));
659+
let pair = Box::new((ptr, arg));
660+
self.args.push(Arg::new(&pair.0));
661+
self.arg_data.push(ManuallyDrop::new(pair));
671662
ptr as *mut ()
672663
}
673-
fn push_raw_ptr<T: 'static>(&mut self, ptr: *mut T) {
674-
self.arg_data.push(Box::new(ptr));
675-
self.args.push(Arg::new(
676-
(self.arg_data.last().unwrap().downcast_ref::<*mut T>()).unwrap_or_else(|| {
677-
panic!("Value wasn't expected type {}", type_name::<*mut T>())
678-
}),
679-
));
664+
fn push_raw_ptr<T: Any>(&mut self, ptr: *mut T) {
665+
let value = Box::new(ptr);
666+
self.args.push(Arg::new(value.as_ref()));
667+
self.arg_data.push(ManuallyDrop::new(value));
680668
}
681669
fn push_value<T: Any>(&mut self, arg: T) -> *mut () {
682-
self.arg_data.push(Box::new(arg));
683-
self.args.push(Arg::new(
684-
(self.arg_data.last().unwrap().downcast_ref::<T>())
685-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>())),
686-
));
687-
(self.arg_data.last().unwrap().downcast_ref::<T>())
688-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
689-
as *const T as *mut ()
670+
let value = Box::new(arg);
671+
let ptr = value.as_ref() as *const T as *mut ();
672+
self.args.push(Arg::new(value.as_ref()));
673+
self.arg_data.push(ManuallyDrop::new(value));
674+
ptr as *const T as *mut ()
690675
}
691676
fn push_repr(&mut self, arg: Vec<u8>) -> *mut () {
692-
self.arg_data.push(Box::new(arg));
693-
self.args.push(Arg::new(
694-
&(self.arg_data.last().unwrap())
695-
.downcast_ref::<Vec<u8>>()
696-
.unwrap()[0],
697-
));
698-
(self.arg_data.last().unwrap().downcast_ref::<Vec<u8>>())
699-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<Vec<u8>>()))
700-
.as_ptr() as *mut ()
677+
let value = Box::new(arg);
678+
self.args.push(Arg::new(&value[0]));
679+
let ptr = value.as_ref().as_ptr();
680+
self.arg_data.push(ManuallyDrop::new(value));
681+
ptr as *mut ()
701682
}
702683
fn push_repr_ptr(&mut self, mut arg: Vec<u8>) -> *mut () {
703684
let ptr = arg.as_mut_ptr();
704-
self.arg_data.push(Box::new((ptr, arg)));
705-
self.args.push(Arg::new(
706-
&(self.arg_data.last().unwrap())
707-
.downcast_ref::<(*mut u8, Vec<u8>)>()
708-
.unwrap_or_else(|| {
709-
panic!(
710-
"Value wasn't expected type {}",
711-
type_name::<(*mut u8, Vec<u8>)>()
712-
)
713-
})
714-
.0,
715-
));
685+
let pair = Box::new((ptr, arg));
686+
self.args.push(Arg::new(&pair.0));
687+
self.arg_data.push(ManuallyDrop::new(pair));
716688
ptr as *mut ()
717689
}
718690
fn push_string(&mut self, arg: String) -> *mut c_char {
719-
let list: Box<[c_char]> = arg
720-
.chars()
721-
.map(|c| c as c_char)
722-
.chain(['\0' as c_char])
723-
.collect();
724-
self.push_list::<c_char>(list)
691+
let arg = CString::new(arg).expect("string should not contain NUL");
692+
let ptr = Box::into_raw(arg.into_bytes_with_nul().into_boxed_slice());
693+
// SAFETY: the pointer was created using `Box::into_raw`
694+
// and `[i8]` is compatible with `[u8]`
695+
let arg = unsafe { Box::from_raw(ptr as *mut [c_char]) };
696+
self.push_list(arg)
725697
}
726-
fn push_list<T: Any + 'static>(&mut self, mut arg: Box<[T]>) -> *mut T {
698+
fn push_list<T: Any>(&mut self, mut arg: Box<[T]>) -> *mut T {
727699
let ptr = if arg.is_empty() {
700+
// TODO: is this special case necessary?
728701
ptr::null_mut()
729702
} else {
730-
&mut arg[0] as *mut T
703+
arg.as_mut_ptr()
731704
};
732705
dbgln!(" create *mut {}: {ptr:p}", type_name::<T>());
733-
let storage = (ptr, arg);
734-
self.arg_data.push(Box::new(storage));
735-
self.args.push(Arg::new(
736-
&(self.arg_data.last_mut().unwrap())
737-
.downcast_mut::<ListStorage<T>>()
738-
.unwrap_or_else(|| {
739-
panic!(
740-
"Value wasn't expected type {}",
741-
type_name::<ListStorage<T>>()
742-
)
743-
})
744-
.0,
745-
));
706+
let storage: ListStorage<_> = (ptr, arg);
707+
let value = Box::new(storage);
708+
self.args.push(Arg::new(&value.0));
709+
self.arg_data.push(ManuallyDrop::new(value));
746710
ptr
747711
}
748712
fn get<T: Any>(&self, index: usize) -> &T {
749-
self.try_get(index).map(|(t, _)| t).unwrap_or_else(|| {
750-
panic!(
751-
"Value wasn't expected type {}, {}, or {}",
752-
type_name::<T>(),
753-
type_name::<(*mut T, Box<T>)>(),
754-
type_name::<ListStorage<T>>()
755-
)
756-
})
713+
self.try_get(index)
714+
.unwrap_or_else(|| {
715+
panic!(
716+
"Value wasn't expected type {}, {}, or {}",
717+
type_name::<T>(),
718+
type_name::<(*mut T, Box<T>)>(),
719+
type_name::<ListStorage<T>>()
720+
)
721+
})
722+
.0
757723
}
758724
fn get_maybe_null<T: Any>(&self, index: usize) -> Option<(&T, Option<*mut T>)> {
759725
self.try_get(index)
760726
.map(Some)
761-
.or_else(|| {
762-
self.arg_data[index]
763-
.downcast_ref::<*mut ()>()
764-
.is_some()
765-
.then_some(None)
766-
})
727+
.or_else(|| self.arg_data[index].is::<*mut ()>().then_some(None))
767728
.unwrap_or_else(|| {
768729
panic!(
769730
"Value wasn't expected type {}, {}, {}, or {}",
@@ -775,47 +736,45 @@ mod enabled {
775736
})
776737
}
777738
fn try_get<T: Any>(&self, index: usize) -> Option<(&T, Option<*mut T>)> {
778-
let any = &self.arg_data[index];
779-
any.downcast_ref::<T>()
739+
self.try_get_as::<T>(index)
780740
.map(|t| {
781741
dbgln!(" exact type");
782742
(t, None)
783743
})
784744
.or_else(|| {
785-
any.downcast_ref::<(*mut T, Box<T>)>().map(|(p, _)| {
745+
self.try_get_as::<(*mut T, Box<T>)>(index).map(|(p, _)| {
786746
dbgln!(" ptr type");
787-
(unsafe { &**p }, Some(*p))
747+
// SAFETY: TODO
748+
(unsafe { p.as_ref().unwrap_unchecked() }, Some(*p))
788749
})
789750
})
790751
.or_else(|| {
791-
any.downcast_ref::<ListStorage<T>>().map(|(_, b)| {
752+
self.try_get_as::<ListStorage<T>>(index).map(|(_, b)| {
792753
dbgln!(" list type");
793-
(&b[0], Some(&b[0] as *const T as *mut T))
754+
(&b[0], Some(b.as_ref().as_ptr() as *mut T))
794755
})
795756
})
796757
}
797-
fn get_list_mut<T: 'static>(&mut self, index: usize) -> (*mut T, &mut Box<[T]>) {
798-
let (ptr, vec) = self.arg_data[index]
799-
.downcast_mut::<ListStorage<T>>()
800-
.unwrap_or_else(|| {
801-
panic!(
802-
"Value wasn't expected type {}",
803-
type_name::<ListStorage<T>>()
804-
)
805-
});
758+
fn get_as_mut<T: Any>(&mut self, index: usize) -> &mut T {
759+
self.try_get_as_mut(index)
760+
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
761+
}
762+
fn get_as<T: Any>(&self, index: usize) -> &T {
763+
self.try_get_as(index)
764+
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
765+
}
766+
fn try_get_as_mut<T: Any>(&mut self, index: usize) -> Option<&mut T> {
767+
self.arg_data[index].downcast_mut()
768+
}
769+
fn try_get_as<T: Any>(&self, index: usize) -> Option<&T> {
770+
self.arg_data[index].downcast_ref()
771+
}
772+
fn get_list_mut<T: Any>(&mut self, index: usize) -> (*mut T, &mut Box<[T]>) {
773+
let (ptr, vec) = self.get_as_mut::<ListStorage<T>>(index);
806774
(*ptr, vec)
807775
}
808776
fn get_repr(&self, index: usize) -> &[u8] {
809-
self.arg_data[index]
810-
.downcast_ref::<(*mut u8, Vec<u8>)>()
811-
.unwrap_or_else(|| {
812-
panic!(
813-
"Value wasn't expected type {}",
814-
type_name::<(*mut u8, Vec<u8>)>()
815-
)
816-
})
817-
.1
818-
.as_slice()
777+
self.get_as::<(*mut u8, Vec<u8>)>(index).1.as_slice()
819778
}
820779

821780
fn bind_arg(&mut self, i: usize, ty: &FfiType, val: &Value) -> Result<*mut (), String> {

0 commit comments

Comments
 (0)