Skip to content

Commit b6640f2

Browse files
authored
Merge pull request #204 from alexcrichton/configure-zalloc
Configure allocation/free functions in zlib/miniz
2 parents b14b216 + c0e3114 commit b6640f2

File tree

1 file changed

+85
-10
lines changed

1 file changed

+85
-10
lines changed

src/ffi.rs

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,14 @@ pub(crate) trait DeflateBackend: Backend {
4242
all(target_arch = "wasm32", not(target_os = "emscripten"))
4343
)))]
4444
pub(crate) mod imp {
45-
use std::{cmp, marker};
45+
use std::alloc::{self, Layout};
46+
use std::cmp;
47+
use std::convert::TryFrom;
48+
use std::marker;
4649
use std::ops::{Deref, DerefMut};
50+
use std::ptr;
4751

48-
pub use libc::{c_int, c_uint};
52+
pub use libc::{c_int, c_uint, c_void, size_t};
4953

5054
use super::*;
5155
use mem::{self, FlushDecompress, Status};
@@ -62,17 +66,84 @@ pub(crate) mod imp {
6266

6367
impl Default for StreamWrapper {
6468
fn default() -> StreamWrapper {
65-
// Temporary workaround due to bug in libz-sys.
66-
// Error non-boxed function pointers in data structure),
67-
// these are not actually used.
68-
#[allow(unknown_lints)]
69-
#[allow(invalid_value)]
7069
StreamWrapper {
71-
inner: Box::new(unsafe { std::mem::zeroed() }),
70+
inner: Box::new(mz_stream {
71+
next_in: ptr::null_mut(),
72+
avail_in: 0,
73+
total_in: 0,
74+
next_out: ptr::null_mut(),
75+
avail_out: 0,
76+
total_out: 0,
77+
msg: ptr::null_mut(),
78+
adler: 0,
79+
data_type: 0,
80+
reserved: 0,
81+
opaque: ptr::null_mut(),
82+
state: ptr::null_mut(),
83+
#[cfg(feature = "zlib")]
84+
zalloc,
85+
#[cfg(feature = "zlib")]
86+
zfree,
87+
#[cfg(not(feature = "zlib"))]
88+
zalloc: Some(zalloc),
89+
#[cfg(not(feature = "zlib"))]
90+
zfree: Some(zfree),
91+
}),
7292
}
7393
}
7494
}
7595

96+
const ALIGN: usize = std::mem::align_of::<usize>();
97+
98+
fn align_up(size: usize, align: usize) -> usize {
99+
(size + align - 1) & !(align - 1)
100+
}
101+
102+
extern "C" fn zalloc(_ptr: *mut c_void, items: AllocSize, item_size: AllocSize) -> *mut c_void {
103+
// We need to multiply `items` and `item_size` to get the actual desired
104+
// allocation size. Since `zfree` doesn't receive a size argument we
105+
// also need to allocate space for a `usize` as a header so we can store
106+
// how large the allocation is to deallocate later.
107+
let size = match items
108+
.checked_mul(item_size)
109+
.and_then(|i| usize::try_from(i).ok())
110+
.map(|size| align_up(size, ALIGN))
111+
.and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
112+
{
113+
Some(i) => i,
114+
None => return ptr::null_mut(),
115+
};
116+
117+
// Make sure the `size` isn't too big to fail `Layout`'s restrictions
118+
let layout = match Layout::from_size_align(size, ALIGN) {
119+
Ok(layout) => layout,
120+
Err(_) => return ptr::null_mut(),
121+
};
122+
123+
unsafe {
124+
// Allocate the data, and if successful store the size we allocated
125+
// at the beginning and then return an offset pointer.
126+
let ptr = alloc::alloc(layout) as *mut usize;
127+
if ptr.is_null() {
128+
return ptr as *mut c_void;
129+
}
130+
*ptr = size;
131+
ptr.add(1) as *mut c_void
132+
}
133+
}
134+
135+
extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
136+
unsafe {
137+
// Move our address being free'd back one pointer, read the size we
138+
// stored in `zalloc`, and then free it using the standard Rust
139+
// allocator.
140+
let ptr = (address as *mut usize).offset(-1);
141+
let size = *ptr;
142+
let layout = Layout::from_size_align_unchecked(size, ALIGN);
143+
alloc::dealloc(ptr as *mut u8, layout)
144+
}
145+
}
146+
76147
impl Deref for StreamWrapper {
77148
type Target = mz_stream;
78149

@@ -314,6 +385,7 @@ pub(crate) mod imp {
314385
extern crate miniz_sys;
315386

316387
pub use self::miniz_sys::*;
388+
pub type AllocSize = libc::size_t;
317389
}
318390

319391
/// Zlib specific
@@ -346,6 +418,7 @@ pub(crate) mod imp {
346418
pub use self::z::Z_STREAM_END as MZ_STREAM_END;
347419
pub use self::z::Z_STREAM_ERROR as MZ_STREAM_ERROR;
348420
pub use self::z::Z_SYNC_FLUSH as MZ_SYNC_FLUSH;
421+
pub type AllocSize = self::z::uInt;
349422

350423
pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;
351424

@@ -370,7 +443,10 @@ pub(crate) mod imp {
370443
mem::size_of::<mz_stream>() as c_int,
371444
)
372445
}
373-
pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int {
446+
pub unsafe extern "C" fn mz_inflateInit2(
447+
stream: *mut mz_stream,
448+
window_bits: c_int,
449+
) -> c_int {
374450
z::inflateInit2_(
375451
stream,
376452
window_bits,
@@ -384,7 +460,6 @@ pub(crate) mod imp {
384460
pub(crate) use self::CInflate as Inflate;
385461
}
386462

387-
388463
/// Implementation for miniz_oxide rust backend.
389464
#[cfg(any(
390465
all(not(feature = "zlib"), feature = "rust_backend"),

0 commit comments

Comments
 (0)