diff --git a/perf-probe/Cargo.toml b/perf-probe/Cargo.toml index 16618bb1..ff4cb5bd 100644 --- a/perf-probe/Cargo.toml +++ b/perf-probe/Cargo.toml @@ -7,6 +7,7 @@ publish = false [features] default = [] xz-core = ["dep:xz-core"] +xz-core-custom-allocator = ["xz-core", "xz-core/custom_allocator"] xz-sys = ["dep:xz-sys"] liblzma-sys = ["dep:liblzma-sys"] diff --git a/perf-probe/src/main.rs b/perf-probe/src/main.rs index 08f3446b..df6dfd97 100644 --- a/perf-probe/src/main.rs +++ b/perf-probe/src/main.rs @@ -23,6 +23,8 @@ use liblzma_sys::{ lzma_index_uncompressed_size, lzma_stream_buffer_bound, lzma_stream_buffer_decode, lzma_stream_flags as BackendStreamFlags, lzma_stream_footer_decode, }; +#[cfg(feature = "xz-core-custom-allocator")] +use xz_core::alloc::{c_allocator, rust_allocator}; #[cfg(feature = "xz-core")] use xz_core::check::{crc32_fast::lzma_crc32, crc64_fast::lzma_crc64}; #[cfg(feature = "xz-core")] @@ -69,6 +71,13 @@ enum InputKind { Text, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum AllocatorPolicy { + Default, + Rust, + C, +} + #[derive(Debug)] struct Config { workload: Workload, @@ -82,6 +91,7 @@ struct Config { preset: u32, iters: usize, warmup: usize, + allocator: AllocatorPolicy, } #[derive(Debug)] @@ -98,14 +108,15 @@ fn main() { }); println!( - "config: backend={} workload={:?} input={:?} size={} preset={} iters={} warmup={}", + "config: backend={} workload={:?} input={:?} size={} preset={} iters={} warmup={} allocator={:?}", BACKEND_NAME, config.workload, config.input_kind, config.size, config.preset, config.iters, - config.warmup + config.warmup, + config.allocator ); if let Some(path) = &config.input_path { println!("input_path: {}", path.display()); @@ -143,6 +154,7 @@ impl Config { preset: 6, iters: 200, warmup: 20, + allocator: AllocatorPolicy::Default, }; while let Some(arg) = args.next() { @@ -188,6 +200,9 @@ impl Config { "--warmup" => { config.warmup = parse_usize(next_arg(&mut args, "--warmup")?, "--warmup")?; } + "--allocator" => { + config.allocator = parse_allocator(next_arg(&mut args, "--allocator")?)?; + } "--help" | "-h" => return Err(usage()), unknown => return Err(format!("unknown argument `{unknown}`\n\n{}", usage())), } @@ -217,6 +232,11 @@ impl Config { return Err("`--chunk-size` is only supported with crc32/crc64 workloads".to_owned()); } + #[cfg(not(feature = "xz-core-custom-allocator"))] + if config.allocator != AllocatorPolicy::Default { + return Err("`--allocator` requires `--features xz-core-custom-allocator`".to_owned()); + } + Ok(config) } } @@ -244,6 +264,7 @@ fn usage() -> String { message.push_str(" --preset <0-9> LZMA preset used by encode/decode prep\n"); message.push_str(" --iters Timed iterations\n"); message.push_str(" --warmup Untimed warmup iterations\n"); + message.push_str(" --allocator xz-core custom_allocator policy probe only\n"); message } @@ -274,6 +295,15 @@ fn parse_input_kind(value: String) -> Result { } } +fn parse_allocator(value: String) -> Result { + match value.as_str() { + "default" => Ok(AllocatorPolicy::Default), + "rust" => Ok(AllocatorPolicy::Rust), + "c" => Ok(AllocatorPolicy::C), + _ => Err(format!("unsupported allocator `{value}`")), + } +} + fn parse_usize(value: String, flag: &str) -> Result { value .parse() @@ -306,7 +336,7 @@ fn load_compressed_input(config: &Config) -> Result<(Vec, usize), std::io::E )), None => { let raw = load_raw_input(config)?; - let compressed = unsafe { backend_encode(&raw, config.preset) }; + let compressed = unsafe { backend_encode(&raw, config.preset, config.allocator) }; Ok((compressed, raw.len())) } } @@ -340,7 +370,7 @@ fn run_encode(config: &Config) { std::process::exit(1); }); - let first = unsafe { backend_encode(&input, config.preset) }; + let first = unsafe { backend_encode(&input, config.preset, config.allocator) }; if let Some(path) = &config.save_output_path { fs::write(path, &first).unwrap_or_else(|err| { eprintln!("failed to write encoded output: {err}"); @@ -349,7 +379,7 @@ fn run_encode(config: &Config) { } let measurement = measure(input.len(), config.iters, config.warmup, || unsafe { - let output = backend_encode(&input, config.preset); + let output = backend_encode(&input, config.preset, config.allocator); fold_bytes(output.len(), &output) }); print_measurement(&measurement, config.iters); @@ -488,18 +518,40 @@ fn fold_bytes(len: usize, data: &[u8]) -> u64 { acc } -unsafe fn backend_encode(input: &[u8], preset: u32) -> Vec { +unsafe fn backend_encode(input: &[u8], preset: u32, allocator: AllocatorPolicy) -> Vec { #[cfg(feature = "xz-core")] let bound = lzma_stream_buffer_bound(input.len()); #[cfg(any(feature = "xz-sys", feature = "liblzma-sys"))] let bound = unsafe { lzma_stream_buffer_bound(input.len()) }; let mut out = vec![0u8; bound]; let mut out_pos: usize = 0; + + #[cfg(feature = "xz-core-custom-allocator")] + let allocator_storage; + #[cfg(feature = "xz-core-custom-allocator")] + let allocator_ptr = match allocator { + AllocatorPolicy::Default => ptr::null(), + AllocatorPolicy::Rust => { + allocator_storage = rust_allocator(); + &allocator_storage + } + AllocatorPolicy::C => { + allocator_storage = c_allocator(); + &allocator_storage + } + }; + + #[cfg(not(feature = "xz-core-custom-allocator"))] + let allocator_ptr = { + debug_assert_eq!(allocator, AllocatorPolicy::Default); + ptr::null() + }; + let ret = unsafe { lzma_easy_buffer_encode( preset, LZMA_CHECK_CRC64, - ptr::null(), + allocator_ptr, input.as_ptr(), input.len(), out.as_mut_ptr(), diff --git a/xz-core/src/alloc.rs b/xz-core/src/alloc.rs index 37e070d5..9382fa9f 100644 --- a/xz-core/src/alloc.rs +++ b/xz-core/src/alloc.rs @@ -1,26 +1,25 @@ -mod rust; - #[cfg(feature = "custom_allocator")] mod c; #[cfg(feature = "custom_allocator")] mod custom; -#[cfg(not(feature = "custom_allocator"))] -mod rust_only; +#[cfg(feature = "custom_allocator")] +mod rust; +#[cfg(not(feature = "custom_allocator"))] +use crate::raw_alloc as policy; #[cfg(feature = "custom_allocator")] use custom as policy; -#[cfg(not(feature = "custom_allocator"))] -use rust_only as policy; #[cfg(feature = "custom_allocator")] pub use c::{c_allocator, c_allocator_ptr, lzma_c_alloc, lzma_c_free}; #[cfg(feature = "custom_allocator")] pub use custom::allocator_or_c; +#[cfg(feature = "custom_allocator")] pub use rust::rust_allocator; pub use policy::{lzma_alloc, lzma_alloc_zero, lzma_free}; pub(crate) use policy::{ internal_alloc_array, internal_alloc_bytes, internal_alloc_object, internal_alloc_zeroed_array, - internal_free, + internal_free, internal_free_array, internal_free_bytes, }; diff --git a/xz-core/src/alloc/custom.rs b/xz-core/src/alloc/custom.rs index 38e8c5aa..5afabd7f 100644 --- a/xz-core/src/alloc/custom.rs +++ b/xz-core/src/alloc/custom.rs @@ -1,7 +1,8 @@ use crate::types::*; use super::c::{c_alloc_bytes, c_alloc_zeroed_bytes, c_allocator_ptr, c_free_ptr}; -use super::rust::{RUST_ALLOC_ALIGN, rust_alloc_impl, rust_allocator_ptr, rust_free_ptr}; +use super::rust::rust_allocator_ptr; +use crate::raw_alloc::{RUST_ALLOC_ALIGN, alloc_impl, free_ptr}; fn c_size(size: size_t) -> size_t { if size == 0 { 1 } else { size } @@ -66,7 +67,7 @@ pub(crate) unsafe fn internal_alloc_bytes( if let Some(alloc) = unsafe { (*allocator).alloc } { return unsafe { alloc((*allocator).opaque, 1, size) }; } - rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) + alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) } pub(crate) unsafe fn internal_alloc_object(allocator: *const lzma_allocator) -> *mut T { @@ -77,7 +78,7 @@ pub(crate) unsafe fn internal_alloc_object(allocator: *const lzma_allocator) alloc((*allocator).opaque, 1, core::mem::size_of::() as size_t) as *mut T }; } - rust_alloc_impl(core::mem::size_of::(), core::mem::align_of::(), false) as *mut T + alloc_impl(core::mem::size_of::(), core::mem::align_of::(), false) as *mut T } pub(crate) unsafe fn internal_alloc_array( @@ -92,7 +93,7 @@ pub(crate) unsafe fn internal_alloc_array( { return unsafe { alloc((*allocator).opaque, 1, size as size_t) as *mut T }; } - rust_alloc_impl(size, core::mem::align_of::(), false) as *mut T + alloc_impl(size, core::mem::align_of::(), false) as *mut T } pub(crate) unsafe fn internal_alloc_zeroed_array( @@ -111,15 +112,27 @@ pub(crate) unsafe fn internal_alloc_zeroed_array( } return ptr; } - rust_alloc_impl(size, core::mem::align_of::(), true) as *mut T + alloc_impl(size, core::mem::align_of::(), true) as *mut T } -pub(crate) unsafe fn internal_free(ptr: *mut c_void, allocator: *const lzma_allocator) { +pub(crate) unsafe fn internal_free_bytes(ptr: *mut c_void, allocator: *const lzma_allocator) { if !allocator.is_null() && let Some(free) = unsafe { (*allocator).free } { unsafe { free((*allocator).opaque, ptr) }; return; } - unsafe { rust_free_ptr(ptr) }; + unsafe { free_ptr(ptr) }; +} + +pub(crate) unsafe fn internal_free(ptr: *mut T, allocator: *const lzma_allocator) { + unsafe { internal_free_bytes(ptr.cast(), allocator) }; +} + +pub(crate) unsafe fn internal_free_array( + ptr: *mut T, + _count: size_t, + allocator: *const lzma_allocator, +) { + unsafe { internal_free_bytes(ptr.cast(), allocator) }; } diff --git a/xz-core/src/alloc/rust.rs b/xz-core/src/alloc/rust.rs index e6fcafb0..8366d574 100644 --- a/xz-core/src/alloc/rust.rs +++ b/xz-core/src/alloc/rust.rs @@ -1,19 +1,8 @@ +use crate::raw_alloc::{RUST_ALLOC_ALIGN, alloc_impl, free_impl}; use crate::types::*; -use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; - -pub(super) const RUST_ALLOC_ALIGN: usize = 16; -const ZERO_SIZE_PTR: *mut c_void = core::ptr::without_provenance_mut(RUST_ALLOC_ALIGN); - -#[derive(Copy, Clone)] -#[repr(C)] -struct RustAllocHeader { - total_size: usize, - align: usize, - offset: usize, -} #[repr(transparent)] -struct StaticAllocator(lzma_allocator); +pub(super) struct StaticAllocator(lzma_allocator); unsafe impl Sync for StaticAllocator {} @@ -23,64 +12,7 @@ static RUST_ALLOCATOR: StaticAllocator = StaticAllocator(lzma_allocator { opaque: core::ptr::null_mut(), }); -const fn round_up(value: usize, align: usize) -> usize { - (value + (align - 1)) & !(align - 1) -} - -pub(super) fn rust_alloc_impl(size: usize, align: usize, zeroed: bool) -> *mut c_void { - if size == 0 { - return ZERO_SIZE_PTR; - } - let align = align - .max(RUST_ALLOC_ALIGN) - .max(core::mem::align_of::()); - let header_size = core::mem::size_of::(); - let Some(value) = header_size.checked_add(align - 1) else { - return core::ptr::null_mut(); - }; - let offset = round_up(value, align); - let Some(total_size) = offset.checked_add(size) else { - return core::ptr::null_mut(); - }; - let Ok(layout) = Layout::from_size_align(total_size, align) else { - return core::ptr::null_mut(); - }; - let base = unsafe { - if zeroed { - alloc_zeroed(layout) - } else { - alloc(layout) - } - }; - if base.is_null() { - return core::ptr::null_mut(); - } - let user_ptr = unsafe { base.add(offset) }; - let header_ptr = unsafe { user_ptr.sub(header_size) as *mut RustAllocHeader }; - unsafe { - header_ptr.write(RustAllocHeader { - total_size, - align, - offset, - }); - } - user_ptr as *mut c_void -} - -pub(super) unsafe fn rust_free_impl(ptr: *mut c_void) { - if ptr.is_null() || ptr == ZERO_SIZE_PTR { - return; - } - let header_size = core::mem::size_of::(); - let user_ptr = ptr as *mut u8; - let header_ptr = unsafe { user_ptr.sub(header_size) as *const RustAllocHeader }; - let header = unsafe { header_ptr.read() }; - let base = unsafe { user_ptr.sub(header.offset) }; - let layout = unsafe { Layout::from_size_align_unchecked(header.total_size, header.align) }; - unsafe { dealloc(base, layout) }; -} - -pub(crate) unsafe fn lzma_rust_alloc( +pub(super) unsafe fn lzma_rust_alloc( _opaque: *mut c_void, nmemb: size_t, size: size_t, @@ -88,23 +20,11 @@ pub(crate) unsafe fn lzma_rust_alloc( let Some(size) = (nmemb as usize).checked_mul(size as usize) else { return core::ptr::null_mut(); }; - rust_alloc_impl(size, RUST_ALLOC_ALIGN, false) -} - -pub(crate) unsafe fn lzma_rust_free(_opaque: *mut c_void, ptr: *mut c_void) { - unsafe { rust_free_impl(ptr) }; -} - -pub(super) unsafe fn rust_alloc_bytes(size: size_t) -> *mut c_void { - rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) + alloc_impl(size, RUST_ALLOC_ALIGN, false) } -pub(super) unsafe fn rust_alloc_zeroed_bytes(size: size_t) -> *mut c_void { - rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, true) -} - -pub(super) unsafe fn rust_free_ptr(ptr: *mut c_void) { - unsafe { rust_free_impl(ptr) }; +pub(super) unsafe fn lzma_rust_free(_opaque: *mut c_void, ptr: *mut c_void) { + unsafe { free_impl(ptr) }; } pub fn rust_allocator() -> lzma_allocator { @@ -114,34 +34,3 @@ pub fn rust_allocator() -> lzma_allocator { pub(super) fn rust_allocator_ptr() -> *const lzma_allocator { &raw const RUST_ALLOCATOR.0 } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn rust_allocator_round_trip() { - unsafe { - let ptr = lzma_rust_alloc(core::ptr::null_mut(), 4, 8); - assert!(!ptr.is_null()); - lzma_rust_free(core::ptr::null_mut(), ptr); - } - } - - #[test] - fn rust_allocation_respects_alignment() { - #[repr(align(32))] - struct Align32([u8; 32]); - - unsafe { - let ptr = rust_alloc_impl( - core::mem::size_of::(), - core::mem::align_of::(), - false, - ); - assert!(!ptr.is_null()); - assert_eq!((ptr as usize) % core::mem::align_of::(), 0); - rust_free_impl(ptr); - } - } -} diff --git a/xz-core/src/alloc/rust_only.rs b/xz-core/src/alloc/rust_only.rs deleted file mode 100644 index 51f15276..00000000 --- a/xz-core/src/alloc/rust_only.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::types::*; - -use super::rust::{rust_alloc_bytes, rust_alloc_impl, rust_alloc_zeroed_bytes, rust_free_ptr}; - -pub unsafe fn lzma_alloc(size: size_t, allocator: *const lzma_allocator) -> *mut c_void { - let _ = allocator; - unsafe { rust_alloc_bytes(size) } -} - -pub unsafe fn lzma_alloc_zero(size: size_t, allocator: *const lzma_allocator) -> *mut c_void { - let _ = allocator; - unsafe { rust_alloc_zeroed_bytes(size) } -} - -pub unsafe fn lzma_free(ptr: *mut c_void, allocator: *const lzma_allocator) { - let _ = allocator; - unsafe { rust_free_ptr(ptr) }; -} - -pub(crate) unsafe fn internal_alloc_bytes( - size: size_t, - allocator: *const lzma_allocator, -) -> *mut c_void { - let _ = allocator; - unsafe { rust_alloc_bytes(size) } -} - -pub(crate) unsafe fn internal_alloc_object(allocator: *const lzma_allocator) -> *mut T { - let _ = allocator; - rust_alloc_impl(core::mem::size_of::(), core::mem::align_of::(), false) as *mut T -} - -pub(crate) unsafe fn internal_alloc_array( - count: size_t, - allocator: *const lzma_allocator, -) -> *mut T { - let _ = allocator; - let Some(size) = (count as usize).checked_mul(core::mem::size_of::()) else { - return core::ptr::null_mut(); - }; - rust_alloc_impl(size, core::mem::align_of::(), false) as *mut T -} - -pub(crate) unsafe fn internal_alloc_zeroed_array( - count: size_t, - allocator: *const lzma_allocator, -) -> *mut T { - let _ = allocator; - let Some(size) = (count as usize).checked_mul(core::mem::size_of::()) else { - return core::ptr::null_mut(); - }; - rust_alloc_impl(size, core::mem::align_of::(), true) as *mut T -} - -pub(crate) unsafe fn internal_free(ptr: *mut c_void, allocator: *const lzma_allocator) { - let _ = allocator; - unsafe { rust_free_ptr(ptr) }; -} diff --git a/xz-core/src/common/alone_decoder.rs b/xz-core/src/common/alone_decoder.rs index 0ea96acd..4b873cad 100644 --- a/xz-core/src/common/alone_decoder.rs +++ b/xz-core/src/common/alone_decoder.rs @@ -144,7 +144,7 @@ unsafe fn alone_decode( unsafe fn alone_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_alone_coder = coder_ptr as *mut lzma_alone_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn alone_decoder_memconfig( coder_ptr: *mut c_void, diff --git a/xz-core/src/common/alone_encoder.rs b/xz-core/src/common/alone_encoder.rs index 10071af8..5f04d207 100644 --- a/xz-core/src/common/alone_encoder.rs +++ b/xz-core/src/common/alone_encoder.rs @@ -62,7 +62,7 @@ unsafe fn alone_encode( unsafe fn alone_encoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_alone_coder = coder_ptr as *mut lzma_alone_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn alone_encoder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/common/auto_decoder.rs b/xz-core/src/common/auto_decoder.rs index 57954212..63caa41f 100644 --- a/xz-core/src/common/auto_decoder.rs +++ b/xz-core/src/common/auto_decoder.rs @@ -92,7 +92,7 @@ unsafe fn auto_decode( unsafe fn auto_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_auto_coder = coder_ptr as *mut lzma_auto_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn auto_decoder_get_check(coder_ptr: *const c_void) -> lzma_check { let coder: *const lzma_auto_coder = coder_ptr as *const lzma_auto_coder; diff --git a/xz-core/src/common/block_decoder.rs b/xz-core/src/common/block_decoder.rs index 8ca3b39b..87a9bf82 100644 --- a/xz-core/src/common/block_decoder.rs +++ b/xz-core/src/common/block_decoder.rs @@ -160,7 +160,7 @@ unsafe fn block_decode( unsafe fn block_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_block_coder = coder_ptr as *mut lzma_block_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } pub(crate) unsafe fn lzma_block_decoder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/common/block_encoder.rs b/xz-core/src/common/block_encoder.rs index 2965d099..bf424e46 100644 --- a/xz-core/src/common/block_encoder.rs +++ b/xz-core/src/common/block_encoder.rs @@ -113,7 +113,7 @@ unsafe fn block_encode( unsafe fn block_encoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_block_coder = coder_ptr as *mut lzma_block_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn block_encoder_update( coder_ptr: *mut c_void, diff --git a/xz-core/src/common/file_info.rs b/xz-core/src/common/file_info.rs index eb917fb0..0d4fcf0f 100644 --- a/xz-core/src/common/file_info.rs +++ b/xz-core/src/common/file_info.rs @@ -456,7 +456,7 @@ unsafe fn file_info_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_a lzma_next_end(::core::ptr::addr_of_mut!((*coder).index_decoder), allocator); lzma_index_end((*coder).this_index, allocator); lzma_index_end((*coder).combined_index, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn lzma_file_info_decoder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/common/index_decoder.rs b/xz-core/src/common/index_decoder.rs index cdbf7c66..312bb303 100644 --- a/xz-core/src/common/index_decoder.rs +++ b/xz-core/src/common/index_decoder.rs @@ -208,7 +208,7 @@ unsafe fn goto_out( unsafe fn index_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_index_coder = coder_ptr as *mut lzma_index_coder; lzma_index_end((*coder).index, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn index_decoder_memconfig( coder_ptr: *mut c_void, diff --git a/xz-core/src/common/index_encoder.rs b/xz-core/src/common/index_encoder.rs index fa93074b..c7105baf 100644 --- a/xz-core/src/common/index_encoder.rs +++ b/xz-core/src/common/index_encoder.rs @@ -130,7 +130,7 @@ unsafe fn index_encode( ret } unsafe fn index_encoder_end(coder: *mut c_void, allocator: *const lzma_allocator) { - crate::alloc::internal_free(coder, allocator); + crate::alloc::internal_free(coder as *mut lzma_index_coder, allocator); } unsafe fn index_encoder_reset(coder: *mut lzma_index_coder, i: *const lzma_index) { lzma_index_iter_init(::core::ptr::addr_of_mut!((*coder).iter), i); diff --git a/xz-core/src/common/lzip_decoder.rs b/xz-core/src/common/lzip_decoder.rs index 64bcc80f..d1e8911b 100644 --- a/xz-core/src/common/lzip_decoder.rs +++ b/xz-core/src/common/lzip_decoder.rs @@ -264,7 +264,7 @@ unsafe fn lzip_decode( unsafe fn lzip_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_lzip_coder = coder_ptr as *mut lzma_lzip_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).lzma_decoder), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn lzip_decoder_get_check(_coder_ptr: *const c_void) -> lzma_check { LZMA_CHECK_CRC32 diff --git a/xz-core/src/common/microlzma_decoder.rs b/xz-core/src/common/microlzma_decoder.rs index 2534e458..36d5295b 100644 --- a/xz-core/src/common/microlzma_decoder.rs +++ b/xz-core/src/common/microlzma_decoder.rs @@ -150,7 +150,7 @@ unsafe fn microlzma_decode( unsafe fn microlzma_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_microlzma_coder = coder_ptr as *mut lzma_microlzma_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).lzma), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn microlzma_decoder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/common/microlzma_encoder.rs b/xz-core/src/common/microlzma_encoder.rs index e0a00fec..5ad4829d 100644 --- a/xz-core/src/common/microlzma_encoder.rs +++ b/xz-core/src/common/microlzma_encoder.rs @@ -56,7 +56,7 @@ unsafe fn microlzma_encode( unsafe fn microlzma_encoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_microlzma_coder = coder_ptr as *mut lzma_microlzma_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).lzma), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn microlzma_encoder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/common/outqueue.rs b/xz-core/src/common/outqueue.rs index 25c67ec7..50f0f71e 100644 --- a/xz-core/src/common/outqueue.rs +++ b/xz-core/src/common/outqueue.rs @@ -25,7 +25,7 @@ unsafe fn free_one_cached_buffer(outq: *mut lzma_outq, allocator: *const lzma_al (*outq).cache = (*buf).next; (*outq).bufs_allocated -= 1; (*outq).mem_allocated -= lzma_outq_outbuf_memusage((*buf).allocated); - crate::alloc::internal_free(buf as *mut c_void, allocator); + crate::alloc::internal_free_bytes(buf as *mut c_void, allocator); } pub unsafe fn lzma_outq_clear_cache(outq: *mut lzma_outq, allocator: *const lzma_allocator) { while !(*outq).cache.is_null() { diff --git a/xz-core/src/common/stream_decoder_mt.rs b/xz-core/src/common/stream_decoder_mt.rs index a79e255e..8af725c2 100644 --- a/xz-core/src/common/stream_decoder_mt.rs +++ b/xz-core/src/common/stream_decoder_mt.rs @@ -153,7 +153,10 @@ unsafe extern "C" fn worker_decoder(thr_ptr: *mut c_void) -> *mut c_void { } else { if (*thr).state == THR_EXIT { mythread_mutex_unlock(::core::ptr::addr_of_mut!((*thr).mutex)); - crate::alloc::internal_free((*thr).in_0 as *mut c_void, worker_allocator(thr)); + crate::alloc::internal_free_bytes( + (*thr).in_0 as *mut c_void, + worker_allocator(thr), + ); lzma_next_end( ::core::ptr::addr_of_mut!((*thr).block_decoder), worker_allocator(thr), @@ -241,7 +244,10 @@ unsafe extern "C" fn worker_decoder(thr_ptr: *mut c_void) -> *mut c_void { mythread_i_434 = 1; } if ret == LZMA_STREAM_END { - crate::alloc::internal_free((*thr).in_0 as *mut c_void, worker_allocator(thr)); + crate::alloc::internal_free_bytes( + (*thr).in_0 as *mut c_void, + worker_allocator(thr), + ); (*thr).in_0 = core::ptr::null_mut(); } let mut mythread_i_458: c_uint = 0; @@ -315,7 +321,7 @@ unsafe fn threads_end(coder: *mut lzma_stream_coder, allocator: *const lzma_allo mythread_join((*(*coder).threads.offset(i_0 as isize)).thread_id); i_0 += 1; } - crate::alloc::internal_free((*coder).threads as *mut c_void, allocator); + crate::alloc::internal_free_array((*coder).threads, (*coder).threads_max as size_t, allocator); (*coder).threads_initialized = 0; (*coder).threads = core::ptr::null_mut(); (*coder).threads_free = core::ptr::null_mut(); @@ -1336,7 +1342,7 @@ unsafe fn stream_decoder_mt_end(coder_ptr: *mut c_void, allocator: *const lzma_a allocator, ); lzma_index_hash_end((*coder).index_hash, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn stream_decoder_mt_get_check(coder_ptr: *const c_void) -> lzma_check { return unsafe { @@ -1468,12 +1474,12 @@ unsafe fn stream_decoder_mt_init( } (*next).coder = coder as *mut c_void; if mythread_mutex_init(::core::ptr::addr_of_mut!((*coder).mutex)) != 0 { - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); return LZMA_MEM_ERROR; } if mythread_cond_init(::core::ptr::addr_of_mut!((*coder).cond)) != 0 { mythread_mutex_destroy(::core::ptr::addr_of_mut!((*coder).mutex)); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); return LZMA_MEM_ERROR; } (*next).code = Some( diff --git a/xz-core/src/common/stream_encoder_mt.rs b/xz-core/src/common/stream_encoder_mt.rs index fdb38bb4..db027ac9 100644 --- a/xz-core/src/common/stream_encoder_mt.rs +++ b/xz-core/src/common/stream_encoder_mt.rs @@ -380,7 +380,7 @@ unsafe extern "C" fn worker_start(thr_ptr: *mut c_void) -> *mut c_void { ::core::ptr::addr_of_mut!((*thr).block_encoder), worker_allocator(thr), ); - crate::alloc::internal_free((*thr).in_0 as *mut c_void, worker_allocator(thr)); + crate::alloc::internal_free_bytes((*thr).in_0 as *mut c_void, worker_allocator(thr)); MYTHREAD_RET_VALUE } unsafe fn threads_stop(coder: *mut lzma_stream_coder, wait_for_threads: bool) { @@ -477,7 +477,7 @@ unsafe fn threads_end(coder: *mut lzma_stream_coder, allocator: *const lzma_allo let _ret: c_int = mythread_join((*(*coder).threads.offset(i_0 as isize)).thread_id); i_0 += 1; } - crate::alloc::internal_free((*coder).threads as *mut c_void, allocator); + crate::alloc::internal_free_array((*coder).threads, (*coder).threads_max as size_t, allocator); } unsafe fn initialize_new_thread( coder: *mut lzma_stream_coder, @@ -526,7 +526,7 @@ unsafe fn initialize_new_thread( } mythread_mutex_destroy(::core::ptr::addr_of_mut!((*thr).mutex)); } - crate::alloc::internal_free((*thr).in_0 as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*thr).in_0 as *mut c_void, allocator); LZMA_MEM_ERROR } unsafe fn get_thread(coder: *mut lzma_stream_coder, allocator: *const lzma_allocator) -> lzma_ret { @@ -971,7 +971,7 @@ unsafe fn stream_encoder_mt_end(coder_ptr: *mut c_void, allocator: *const lzma_a lzma_index_end((*coder).index, allocator); mythread_cond_destroy(::core::ptr::addr_of_mut!((*coder).cond)); mythread_mutex_destroy(::core::ptr::addr_of_mut!((*coder).mutex)); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn stream_encoder_mt_update( coder_ptr: *mut c_void, @@ -1107,13 +1107,13 @@ unsafe fn stream_encoder_mt_create_coder( } (*next).coder = coder as *mut c_void; if mythread_mutex_init(::core::ptr::addr_of_mut!((*coder).mutex)) != 0 { - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); (*next).coder = core::ptr::null_mut(); return core::ptr::null_mut(); } if mythread_cond_init(::core::ptr::addr_of_mut!((*coder).cond)) != 0 { mythread_mutex_destroy(::core::ptr::addr_of_mut!((*coder).mutex)); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); (*next).coder = core::ptr::null_mut(); return core::ptr::null_mut(); } diff --git a/xz-core/src/delta/delta_common.rs b/xz-core/src/delta/delta_common.rs index 59103301..35efa6e6 100644 --- a/xz-core/src/delta/delta_common.rs +++ b/xz-core/src/delta/delta_common.rs @@ -2,7 +2,7 @@ use crate::types::*; unsafe fn delta_coder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_delta_coder = coder_ptr as *mut lzma_delta_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } pub unsafe fn lzma_delta_coder_init( next: *mut lzma_next_coder, diff --git a/xz-core/src/lib.rs b/xz-core/src/lib.rs index 72878252..6c564bfc 100644 --- a/xz-core/src/lib.rs +++ b/xz-core/src/lib.rs @@ -21,6 +21,7 @@ pub mod delta; pub mod lz; pub mod lzma; pub mod rangecoder; +mod raw_alloc; pub mod simple; pub mod tuklib; pub mod types; diff --git a/xz-core/src/lz/lz_decoder.rs b/xz-core/src/lz/lz_decoder.rs index 10818c11..86dbaf42 100644 --- a/xz-core/src/lz/lz_decoder.rs +++ b/xz-core/src/lz/lz_decoder.rs @@ -166,13 +166,13 @@ unsafe fn lz_decode( unsafe fn lz_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_coder = coder_ptr as *mut lzma_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free((*coder).dict.buf as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*coder).dict.buf as *mut c_void, allocator); if let Some(end) = (*coder).lz.end { end((*coder).lz.coder, allocator); } else { - crate::alloc::internal_free((*coder).lz.coder, allocator); + crate::alloc::internal_free_bytes((*coder).lz.coder, allocator); } - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } pub unsafe fn lzma_lz_decoder_init( next: *mut lzma_next_coder, @@ -258,7 +258,7 @@ pub unsafe fn lzma_lz_decoder_init( .dict_size .wrapping_add((2 * LZ_DICT_REPEAT_MAX) as size_t); if (*coder).dict.size != alloc_size { - crate::alloc::internal_free((*coder).dict.buf as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*coder).dict.buf as *mut c_void, allocator); (*coder).dict.buf = crate::alloc::internal_alloc_bytes( alloc_size.wrapping_add(LZ_DICT_EXTRA as size_t), allocator, diff --git a/xz-core/src/lz/lz_encoder.rs b/xz-core/src/lz/lz_encoder.rs index 998cd16b..eceab1d5 100644 --- a/xz-core/src/lz/lz_encoder.rs +++ b/xz-core/src/lz/lz_encoder.rs @@ -159,7 +159,11 @@ unsafe fn lz_encoder_prepare( let old_size: u32 = (*mf).size; (*mf).size = (*mf).keep_size_before + reserve + (*mf).keep_size_after; if !(*mf).buffer.is_null() && old_size != (*mf).size { - crate::alloc::internal_free((*mf).buffer as *mut c_void, allocator); + crate::alloc::internal_free_array( + (*mf).buffer, + (old_size + LZMA_MEMCMPLEN_EXTRA) as size_t, + allocator, + ); (*mf).buffer = core::ptr::null_mut(); } (*mf).match_len_max = (*lz_options).match_len_max as u32; @@ -225,9 +229,9 @@ unsafe fn lz_encoder_prepare( (*mf).sons_count *= 2; } if old_hash_count != (*mf).hash_count || old_sons_count != (*mf).sons_count { - crate::alloc::internal_free((*mf).hash as *mut c_void, allocator); + crate::alloc::internal_free_array((*mf).hash, old_hash_count as size_t, allocator); (*mf).hash = core::ptr::null_mut(); - crate::alloc::internal_free((*mf).son as *mut c_void, allocator); + crate::alloc::internal_free_array((*mf).son, old_sons_count as size_t, allocator); (*mf).son = core::ptr::null_mut(); } (*mf).depth = (*lz_options).depth; @@ -246,10 +250,10 @@ unsafe fn lz_encoder_init( lz_options: *const lzma_lz_options, ) -> bool { if (*mf).buffer.is_null() { - (*mf).buffer = crate::alloc::internal_alloc_bytes( + (*mf).buffer = crate::alloc::internal_alloc_array::( ((*mf).size + LZMA_MEMCMPLEN_EXTRA) as size_t, allocator, - ) as *mut u8; + ); if (*mf).buffer.is_null() { return true; } @@ -271,9 +275,9 @@ unsafe fn lz_encoder_init( (*mf).son = crate::alloc::internal_alloc_array::((*mf).sons_count as size_t, allocator); if (*mf).hash.is_null() || (*mf).son.is_null() { - crate::alloc::internal_free((*mf).hash as *mut c_void, allocator); + crate::alloc::internal_free_array((*mf).hash, (*mf).hash_count as size_t, allocator); (*mf).hash = core::ptr::null_mut(); - crate::alloc::internal_free((*mf).son as *mut c_void, allocator); + crate::alloc::internal_free_array((*mf).son, (*mf).sons_count as size_t, allocator); (*mf).son = core::ptr::null_mut(); return true; } @@ -341,15 +345,23 @@ pub fn lzma_lz_encoder_memusage(lz_options: *const lzma_lz_options) -> u64 { unsafe fn lz_encoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_coder = coder_ptr as *mut lzma_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free((*coder).mf.son as *mut c_void, allocator); - crate::alloc::internal_free((*coder).mf.hash as *mut c_void, allocator); - crate::alloc::internal_free((*coder).mf.buffer as *mut c_void, allocator); + crate::alloc::internal_free_array((*coder).mf.son, (*coder).mf.sons_count as size_t, allocator); + crate::alloc::internal_free_array( + (*coder).mf.hash, + (*coder).mf.hash_count as size_t, + allocator, + ); + crate::alloc::internal_free_array( + (*coder).mf.buffer, + ((*coder).mf.size + LZMA_MEMCMPLEN_EXTRA) as size_t, + allocator, + ); if let Some(end) = (*coder).lz.end { end((*coder).lz.coder, allocator); } else { - crate::alloc::internal_free((*coder).lz.coder, allocator); + crate::alloc::internal_free_bytes((*coder).lz.coder, allocator); } - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn lz_encoder_update( coder_ptr: *mut c_void, diff --git a/xz-core/src/lzma/lzma2_decoder.rs b/xz-core/src/lzma/lzma2_decoder.rs index ed016b0d..83a1ab8b 100644 --- a/xz-core/src/lzma/lzma2_decoder.rs +++ b/xz-core/src/lzma/lzma2_decoder.rs @@ -195,8 +195,8 @@ unsafe fn lzma2_decode( } unsafe fn lzma2_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_lzma2_coder = coder_ptr as *mut lzma_lzma2_coder; - crate::alloc::internal_free((*coder).lzma.coder, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*coder).lzma.coder, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn lzma2_decoder_init( lz: *mut lzma_lz_decoder, diff --git a/xz-core/src/lzma/lzma2_encoder.rs b/xz-core/src/lzma/lzma2_encoder.rs index 104cbe17..6eb03e24 100644 --- a/xz-core/src/lzma/lzma2_encoder.rs +++ b/xz-core/src/lzma/lzma2_encoder.rs @@ -222,8 +222,8 @@ unsafe fn lzma2_encode( } unsafe fn lzma2_encoder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_lzma2_coder = coder_ptr as *mut lzma_lzma2_coder; - crate::alloc::internal_free((*coder).lzma, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*coder).lzma, allocator); + crate::alloc::internal_free(coder, allocator); } unsafe fn lzma2_encoder_options_update( coder_ptr: *mut c_void, diff --git a/xz-core/src/lzma/lzma_decoder.rs b/xz-core/src/lzma/lzma_decoder.rs index d826b4a8..3f193fb9 100644 --- a/xz-core/src/lzma/lzma_decoder.rs +++ b/xz-core/src/lzma/lzma_decoder.rs @@ -2368,8 +2368,10 @@ pub unsafe fn lzma_lzma_decoder_create( lz_options: *mut lzma_lz_options, ) -> lzma_ret { if (*lz).coder.is_null() { - (*lz).coder = - crate::alloc::internal_alloc_object::(allocator) as *mut c_void; + (*lz).coder = crate::alloc::internal_alloc_bytes( + core::mem::size_of::() as size_t, + allocator, + ); if (*lz).coder.is_null() { return LZMA_MEM_ERROR; } diff --git a/xz-core/src/lzma/lzma_encoder.rs b/xz-core/src/lzma/lzma_encoder.rs index 75d474f2..e49c1c7e 100644 --- a/xz-core/src/lzma/lzma_encoder.rs +++ b/xz-core/src/lzma/lzma_encoder.rs @@ -1038,8 +1038,10 @@ pub unsafe fn lzma_lzma_encoder_create( lz_options: *mut lzma_lz_options, ) -> lzma_ret { if (*coder_ptr).is_null() { - *coder_ptr = - crate::alloc::internal_alloc_object::(allocator) as *mut c_void; + *coder_ptr = crate::alloc::internal_alloc_bytes( + core::mem::size_of::() as size_t, + allocator, + ); if (*coder_ptr).is_null() { return LZMA_MEM_ERROR; } diff --git a/xz-core/src/raw_alloc.rs b/xz-core/src/raw_alloc.rs new file mode 100644 index 00000000..24300d76 --- /dev/null +++ b/xz-core/src/raw_alloc.rs @@ -0,0 +1,209 @@ +use crate::types::*; +use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; + +pub(crate) const RUST_ALLOC_ALIGN: usize = 16; +const ZERO_SIZE_PTR: *mut c_void = core::ptr::without_provenance_mut(RUST_ALLOC_ALIGN); + +#[derive(Copy, Clone)] +#[repr(C)] +struct RustAllocHeader { + total_size: usize, + align: usize, + offset: usize, +} + +const fn round_up(value: usize, align: usize) -> usize { + (value + (align - 1)) & !(align - 1) +} + +pub(crate) fn alloc_impl(size: usize, align: usize, zeroed: bool) -> *mut c_void { + if size == 0 { + return ZERO_SIZE_PTR; + } + let align = align + .max(RUST_ALLOC_ALIGN) + .max(core::mem::align_of::()); + let header_size = core::mem::size_of::(); + let Some(value) = header_size.checked_add(align - 1) else { + return core::ptr::null_mut(); + }; + let offset = round_up(value, align); + let Some(total_size) = offset.checked_add(size) else { + return core::ptr::null_mut(); + }; + let Ok(layout) = Layout::from_size_align(total_size, align) else { + return core::ptr::null_mut(); + }; + let base = unsafe { + if zeroed { + alloc_zeroed(layout) + } else { + alloc(layout) + } + }; + if base.is_null() { + return core::ptr::null_mut(); + } + let user_ptr = unsafe { base.add(offset) }; + let header_ptr = unsafe { user_ptr.sub(header_size) as *mut RustAllocHeader }; + unsafe { + header_ptr.write(RustAllocHeader { + total_size, + align, + offset, + }); + } + user_ptr as *mut c_void +} + +fn raw_layout(size: usize, align: usize) -> Option { + Layout::from_size_align(size, align.max(RUST_ALLOC_ALIGN)).ok() +} + +pub(crate) unsafe fn free_impl(ptr: *mut c_void) { + if ptr.is_null() || ptr == ZERO_SIZE_PTR { + return; + } + let header_size = core::mem::size_of::(); + let user_ptr = ptr as *mut u8; + let header_ptr = unsafe { user_ptr.sub(header_size) as *const RustAllocHeader }; + let header = unsafe { header_ptr.read() }; + let base = unsafe { user_ptr.sub(header.offset) }; + let layout = unsafe { Layout::from_size_align_unchecked(header.total_size, header.align) }; + unsafe { dealloc(base, layout) }; +} + +pub(crate) unsafe fn alloc_bytes(size: size_t) -> *mut c_void { + alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) +} + +pub(crate) unsafe fn alloc_zeroed_bytes(size: size_t) -> *mut c_void { + alloc_impl(size as usize, RUST_ALLOC_ALIGN, true) +} + +pub(crate) unsafe fn free_ptr(ptr: *mut c_void) { + unsafe { free_impl(ptr) }; +} + +pub unsafe fn lzma_alloc(size: size_t, _allocator: *const lzma_allocator) -> *mut c_void { + unsafe { alloc_bytes(size) } +} + +pub unsafe fn lzma_alloc_zero(size: size_t, _allocator: *const lzma_allocator) -> *mut c_void { + unsafe { alloc_zeroed_bytes(size) } +} + +pub unsafe fn lzma_free(ptr: *mut c_void, _allocator: *const lzma_allocator) { + unsafe { free_ptr(ptr) }; +} + +pub(crate) unsafe fn internal_alloc_bytes( + size: size_t, + _allocator: *const lzma_allocator, +) -> *mut c_void { + unsafe { alloc_bytes(size) } +} + +pub(crate) unsafe fn internal_alloc_object(_allocator: *const lzma_allocator) -> *mut T { + let Some(layout) = raw_layout(core::mem::size_of::(), core::mem::align_of::()) else { + return core::ptr::null_mut(); + }; + if layout.size() == 0 { + return core::ptr::NonNull::::dangling().as_ptr(); + } + unsafe { alloc(layout).cast::() } +} + +pub(crate) unsafe fn internal_alloc_array( + count: size_t, + _allocator: *const lzma_allocator, +) -> *mut T { + let Some(size) = (count as usize).checked_mul(core::mem::size_of::()) else { + return core::ptr::null_mut(); + }; + let Some(layout) = raw_layout(size, core::mem::align_of::()) else { + return core::ptr::null_mut(); + }; + if layout.size() == 0 { + return core::ptr::NonNull::::dangling().as_ptr(); + } + unsafe { alloc(layout).cast::() } +} + +pub(crate) unsafe fn internal_alloc_zeroed_array( + count: size_t, + _allocator: *const lzma_allocator, +) -> *mut T { + let Some(size) = (count as usize).checked_mul(core::mem::size_of::()) else { + return core::ptr::null_mut(); + }; + let Some(layout) = raw_layout(size, core::mem::align_of::()) else { + return core::ptr::null_mut(); + }; + if layout.size() == 0 { + return core::ptr::NonNull::::dangling().as_ptr(); + } + unsafe { alloc_zeroed(layout).cast::() } +} + +pub(crate) unsafe fn internal_free_bytes(ptr: *mut c_void, _allocator: *const lzma_allocator) { + unsafe { free_ptr(ptr) }; +} + +pub(crate) unsafe fn internal_free(ptr: *mut T, _allocator: *const lzma_allocator) { + if ptr.is_null() || core::mem::size_of::() == 0 { + return; + } + let Some(layout) = raw_layout(core::mem::size_of::(), core::mem::align_of::()) else { + return; + }; + unsafe { dealloc(ptr.cast::(), layout) }; +} + +pub(crate) unsafe fn internal_free_array( + ptr: *mut T, + count: size_t, + _allocator: *const lzma_allocator, +) { + let Some(size) = (count as usize).checked_mul(core::mem::size_of::()) else { + return; + }; + let Some(layout) = raw_layout(size, core::mem::align_of::()) else { + return; + }; + if ptr.is_null() || layout.size() == 0 { + return; + } + unsafe { dealloc(ptr.cast::(), layout) }; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn raw_allocator_round_trip() { + unsafe { + let ptr = alloc_bytes(32); + assert!(!ptr.is_null()); + free_ptr(ptr); + } + } + + #[test] + fn raw_allocation_respects_alignment() { + #[repr(align(32))] + struct Align32([u8; 32]); + + unsafe { + let ptr = alloc_impl( + core::mem::size_of::(), + core::mem::align_of::(), + false, + ); + assert!(!ptr.is_null()); + assert_eq!((ptr as usize) % core::mem::align_of::(), 0); + free_impl(ptr); + } + } +} diff --git a/xz-core/src/simple/simple_coder.rs b/xz-core/src/simple/simple_coder.rs index dff34656..9d41d96a 100644 --- a/xz-core/src/simple/simple_coder.rs +++ b/xz-core/src/simple/simple_coder.rs @@ -175,8 +175,8 @@ unsafe fn simple_code( unsafe fn simple_coder_end(coder_ptr: *mut c_void, allocator: *const lzma_allocator) { let coder: *mut lzma_simple_coder = coder_ptr as *mut lzma_simple_coder; lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); - crate::alloc::internal_free((*coder).simple, allocator); - crate::alloc::internal_free(coder as *mut c_void, allocator); + crate::alloc::internal_free_bytes((*coder).simple, allocator); + crate::alloc::internal_free_bytes(coder as *mut c_void, allocator); } unsafe fn simple_coder_update( coder_ptr: *mut c_void,