Skip to content

Commit d4a0d6c

Browse files
committed
fix(ffi): use ManuallyDrop to leak memory for Uiua code to free
1 parent 7ad6330 commit d4a0d6c

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

@@ -641,10 +641,10 @@ mod enabled {
641641

642642
type ListStorage<T> = (*mut T, Box<[T]>);
643643

644-
#[derive(Default)]
644+
#[derive(Default, Debug)]
645645
struct FfiBindings {
646-
arg_data: Vec<Box<dyn Any>>,
647-
other_data: Vec<Box<dyn Any>>,
646+
arg_data: Vec<ManuallyDrop<Box<dyn Any>>>,
647+
other_data: Vec<ManuallyDrop<Box<dyn Any>>>,
648648
args: Vec<Arg>,
649649
}
650650

@@ -654,118 +654,79 @@ mod enabled {
654654
self.args.pop().unwrap();
655655
self.other_data.push(self.arg_data.pop().unwrap());
656656
}
657-
fn alloc_and_push_ptr_to<T: Any + Copy + std::fmt::Debug>(&mut self, arg: T) -> *mut () {
658-
let mut bx = Box::<T>::new(arg);
659-
let ptr: *mut T = &mut *bx;
657+
fn alloc_and_push_ptr_to<T: Any>(&mut self, arg: T) -> *mut () {
658+
let mut arg = Box::new(arg);
659+
let ptr: *mut T = arg.as_mut();
660660
dbgln!(" create *mut {}: {ptr:p}", type_name::<T>());
661-
self.arg_data.push(Box::new((ptr, bx)));
662-
self.args.push(Arg::new(
663-
&(self.arg_data.last().unwrap())
664-
.downcast_ref::<(*mut T, Box<T>)>()
665-
.unwrap_or_else(|| {
666-
panic!(
667-
"Value wasn't expected type {}",
668-
type_name::<(*mut T, Box<T>)>()
669-
)
670-
})
671-
.0,
672-
));
661+
let pair = Box::new((ptr, arg));
662+
self.args.push(Arg::new(&pair.0));
663+
self.arg_data.push(ManuallyDrop::new(pair));
673664
ptr as *mut ()
674665
}
675-
fn push_raw_ptr<T: 'static>(&mut self, ptr: *mut T) {
676-
self.arg_data.push(Box::new(ptr));
677-
self.args.push(Arg::new(
678-
(self.arg_data.last().unwrap().downcast_ref::<*mut T>()).unwrap_or_else(|| {
679-
panic!("Value wasn't expected type {}", type_name::<*mut T>())
680-
}),
681-
));
666+
fn push_raw_ptr<T: Any>(&mut self, ptr: *mut T) {
667+
let value = Box::new(ptr);
668+
self.args.push(Arg::new(value.as_ref()));
669+
self.arg_data.push(ManuallyDrop::new(value));
682670
}
683671
fn push_value<T: Any>(&mut self, arg: T) -> *mut () {
684-
self.arg_data.push(Box::new(arg));
685-
self.args.push(Arg::new(
686-
(self.arg_data.last().unwrap().downcast_ref::<T>())
687-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>())),
688-
));
689-
(self.arg_data.last().unwrap().downcast_ref::<T>())
690-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
691-
as *const T as *mut ()
672+
let value = Box::new(arg);
673+
let ptr = value.as_ref() as *const T as *mut ();
674+
self.args.push(Arg::new(value.as_ref()));
675+
self.arg_data.push(ManuallyDrop::new(value));
676+
ptr as *const T as *mut ()
692677
}
693678
fn push_repr(&mut self, arg: Vec<u8>) -> *mut () {
694-
self.arg_data.push(Box::new(arg));
695-
self.args.push(Arg::new(
696-
&(self.arg_data.last().unwrap())
697-
.downcast_ref::<Vec<u8>>()
698-
.unwrap()[0],
699-
));
700-
(self.arg_data.last().unwrap().downcast_ref::<Vec<u8>>())
701-
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<Vec<u8>>()))
702-
.as_ptr() as *mut ()
679+
let value = Box::new(arg);
680+
self.args.push(Arg::new(&value[0]));
681+
let ptr = value.as_ref().as_ptr();
682+
self.arg_data.push(ManuallyDrop::new(value));
683+
ptr as *mut ()
703684
}
704685
fn push_repr_ptr(&mut self, mut arg: Vec<u8>) -> *mut () {
705686
let ptr = arg.as_mut_ptr();
706-
self.arg_data.push(Box::new((ptr, arg)));
707-
self.args.push(Arg::new(
708-
&(self.arg_data.last().unwrap())
709-
.downcast_ref::<(*mut u8, Vec<u8>)>()
710-
.unwrap_or_else(|| {
711-
panic!(
712-
"Value wasn't expected type {}",
713-
type_name::<(*mut u8, Vec<u8>)>()
714-
)
715-
})
716-
.0,
717-
));
687+
let pair = Box::new((ptr, arg));
688+
self.args.push(Arg::new(&pair.0));
689+
self.arg_data.push(ManuallyDrop::new(pair));
718690
ptr as *mut ()
719691
}
720692
fn push_string(&mut self, arg: String) -> *mut c_char {
721-
let list: Box<[c_char]> = arg
722-
.chars()
723-
.map(|c| c as c_char)
724-
.chain(['\0' as c_char])
725-
.collect();
726-
self.push_list::<c_char>(list)
693+
let arg = CString::new(arg).expect("string should not contain NUL");
694+
let ptr = Box::into_raw(arg.into_bytes_with_nul().into_boxed_slice());
695+
// SAFETY: the pointer was created using `Box::into_raw`
696+
// and `[i8]` is compatible with `[u8]`
697+
let arg = unsafe { Box::from_raw(ptr as *mut [c_char]) };
698+
self.push_list(arg)
727699
}
728-
fn push_list<T: Any + 'static>(&mut self, mut arg: Box<[T]>) -> *mut T {
700+
fn push_list<T: Any>(&mut self, mut arg: Box<[T]>) -> *mut T {
729701
let ptr = if arg.is_empty() {
702+
// TODO: is this special case necessary?
730703
ptr::null_mut()
731704
} else {
732-
&mut arg[0] as *mut T
705+
arg.as_mut_ptr()
733706
};
734707
dbgln!(" create *mut {}: {ptr:p}", type_name::<T>());
735-
let storage = (ptr, arg);
736-
self.arg_data.push(Box::new(storage));
737-
self.args.push(Arg::new(
738-
&(self.arg_data.last_mut().unwrap())
739-
.downcast_mut::<ListStorage<T>>()
740-
.unwrap_or_else(|| {
741-
panic!(
742-
"Value wasn't expected type {}",
743-
type_name::<ListStorage<T>>()
744-
)
745-
})
746-
.0,
747-
));
708+
let storage: ListStorage<_> = (ptr, arg);
709+
let value = Box::new(storage);
710+
self.args.push(Arg::new(&value.0));
711+
self.arg_data.push(ManuallyDrop::new(value));
748712
ptr
749713
}
750714
fn get<T: Any>(&self, index: usize) -> &T {
751-
self.try_get(index).map(|(t, _)| t).unwrap_or_else(|| {
752-
panic!(
753-
"Value wasn't expected type {}, {}, or {}",
754-
type_name::<T>(),
755-
type_name::<(*mut T, Box<T>)>(),
756-
type_name::<ListStorage<T>>()
757-
)
758-
})
715+
self.try_get(index)
716+
.unwrap_or_else(|| {
717+
panic!(
718+
"Value wasn't expected type {}, {}, or {}",
719+
type_name::<T>(),
720+
type_name::<(*mut T, Box<T>)>(),
721+
type_name::<ListStorage<T>>()
722+
)
723+
})
724+
.0
759725
}
760726
fn get_maybe_null<T: Any>(&self, index: usize) -> Option<(&T, Option<*mut T>)> {
761727
self.try_get(index)
762728
.map(Some)
763-
.or_else(|| {
764-
self.arg_data[index]
765-
.downcast_ref::<*mut ()>()
766-
.is_some()
767-
.then_some(None)
768-
})
729+
.or_else(|| self.arg_data[index].is::<*mut ()>().then_some(None))
769730
.unwrap_or_else(|| {
770731
panic!(
771732
"Value wasn't expected type {}, {}, {}, or {}",
@@ -777,47 +738,45 @@ mod enabled {
777738
})
778739
}
779740
fn try_get<T: Any>(&self, index: usize) -> Option<(&T, Option<*mut T>)> {
780-
let any = &self.arg_data[index];
781-
any.downcast_ref::<T>()
741+
self.try_get_as::<T>(index)
782742
.map(|t| {
783743
dbgln!(" exact type");
784744
(t, None)
785745
})
786746
.or_else(|| {
787-
any.downcast_ref::<(*mut T, Box<T>)>().map(|(p, _)| {
747+
self.try_get_as::<(*mut T, Box<T>)>(index).map(|(p, _)| {
788748
dbgln!(" ptr type");
789-
(unsafe { &**p }, Some(*p))
749+
// SAFETY: TODO
750+
(unsafe { p.as_ref().unwrap_unchecked() }, Some(*p))
790751
})
791752
})
792753
.or_else(|| {
793-
any.downcast_ref::<ListStorage<T>>().map(|(_, b)| {
754+
self.try_get_as::<ListStorage<T>>(index).map(|(_, b)| {
794755
dbgln!(" list type");
795-
(&b[0], Some(&b[0] as *const T as *mut T))
756+
(&b[0], Some(b.as_ref().as_ptr() as *mut T))
796757
})
797758
})
798759
}
799-
fn get_list_mut<T: 'static>(&mut self, index: usize) -> (*mut T, &mut Box<[T]>) {
800-
let (ptr, vec) = self.arg_data[index]
801-
.downcast_mut::<ListStorage<T>>()
802-
.unwrap_or_else(|| {
803-
panic!(
804-
"Value wasn't expected type {}",
805-
type_name::<ListStorage<T>>()
806-
)
807-
});
760+
fn get_as_mut<T: Any>(&mut self, index: usize) -> &mut T {
761+
self.try_get_as_mut(index)
762+
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
763+
}
764+
fn get_as<T: Any>(&self, index: usize) -> &T {
765+
self.try_get_as(index)
766+
.unwrap_or_else(|| panic!("Value wasn't expected type {}", type_name::<T>()))
767+
}
768+
fn try_get_as_mut<T: Any>(&mut self, index: usize) -> Option<&mut T> {
769+
self.arg_data[index].downcast_mut()
770+
}
771+
fn try_get_as<T: Any>(&self, index: usize) -> Option<&T> {
772+
self.arg_data[index].downcast_ref()
773+
}
774+
fn get_list_mut<T: Any>(&mut self, index: usize) -> (*mut T, &mut Box<[T]>) {
775+
let (ptr, vec) = self.get_as_mut::<ListStorage<T>>(index);
808776
(*ptr, vec)
809777
}
810778
fn get_repr(&self, index: usize) -> &[u8] {
811-
self.arg_data[index]
812-
.downcast_ref::<(*mut u8, Vec<u8>)>()
813-
.unwrap_or_else(|| {
814-
panic!(
815-
"Value wasn't expected type {}",
816-
type_name::<(*mut u8, Vec<u8>)>()
817-
)
818-
})
819-
.1
820-
.as_slice()
779+
self.get_as::<(*mut u8, Vec<u8>)>(index).1.as_slice()
821780
}
822781

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

0 commit comments

Comments
 (0)