From ab6f23fdf2700b879b3c204e7792e9faf81d1d59 Mon Sep 17 00:00:00 2001 From: Dan Pashin Date: Fri, 14 Jun 2024 11:14:16 +0300 Subject: [PATCH] Fix possible bug when allocator in FFI is not malloc when requesting packages --- .../Twackup/Sources/FFI Models/Dpkg.swift | 2 +- twackup/src/ffi/c_dpkg.rs | 4 ++-- twackup/src/ffi/mod.rs | 19 ++++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/twackup-gui/Twackup/Sources/FFI Models/Dpkg.swift b/twackup-gui/Twackup/Sources/FFI Models/Dpkg.swift index 4d253f3..afcd42d 100644 --- a/twackup-gui/Twackup/Sources/FFI Models/Dpkg.swift +++ b/twackup-gui/Twackup/Sources/FFI Models/Dpkg.swift @@ -56,7 +56,7 @@ actor Dpkg { let count = tw_get_packages(innerDpkg, onlyLeaves, TW_PACKAGES_SORT_NAME.clampedToU8, &packagesPtr) let buffer = UnsafeBufferPointer(start: packagesPtr, count: Int(count)) - defer { buffer.deallocate() } + defer { tw_free_packages(packagesPtr, count) } return buffer.compactMap { package in let model = FFIPackage(package) diff --git a/twackup/src/ffi/c_dpkg.rs b/twackup/src/ffi/c_dpkg.rs index a54c36b..6180370 100644 --- a/twackup/src/ffi/c_dpkg.rs +++ b/twackup/src/ffi/c_dpkg.rs @@ -91,10 +91,10 @@ impl TwDpkg { let packages: Option> = tokio_rt.block_on(async { if sort == TwPackagesSort::Unsorted { let packages = dpkg.unsorted_packages(leaves_only).await.ok()?; - Some(packages.into_iter().map(TwPackage::from).collect()) + Some(packages.into_iter().map(Into::into).collect()) } else { let packages = dpkg.packages(leaves_only, sort.into()).await.ok()?; - Some(packages.into_values().map(TwPackage::from).collect()) + Some(packages.into_values().map(Into::into).collect()) } }); diff --git a/twackup/src/ffi/mod.rs b/twackup/src/ffi/mod.rs index 8f9b8a9..9d9193a 100644 --- a/twackup/src/ffi/mod.rs +++ b/twackup/src/ffi/mod.rs @@ -37,7 +37,7 @@ use crate::{ Dpkg, }; use safer_ffi::{boxed, derive_ReprC, ffi_export, prelude::c_slice, prelude::char_p}; -use std::{mem, mem::ManuallyDrop, ptr::NonNull}; +use std::{mem, mem::ManuallyDrop, ptr::NonNull, slice}; #[derive_ReprC] #[repr(i8)] @@ -82,6 +82,15 @@ fn tw_get_packages( if let Some(packages) = dpkg.get_packages(leaves_only, sort) { let packages = ManuallyDrop::new(packages); + // Since memory allocators for Rust and outer FFI callee can be different + // we must release slice by ourselves + // + // To do that, slice must have valid length and layout + // Releasing func will decrement counter on ARC, so we need to increase it here + for package in packages.as_slice() { + package.inner.retain(); + } + let packages_ptr = packages.as_ptr().cast_mut(); unsafe { output.write(NonNull::new_unchecked(packages_ptr)) }; @@ -91,6 +100,14 @@ fn tw_get_packages( } } +#[ffi_export] +fn tw_free_packages(mut start: NonNull, length: i64) { + unsafe { + let packages = slice::from_raw_parts_mut(start.as_mut(), length as usize); + drop(Box::from_raw(packages)) + } +} + /// Returns package section description /// /// \param[in] package package instance