Skip to content

Commit 2113148

Browse files
brianpanefolkertdev
authored andcommitted
Reserve half of the GzState input buffer space for gzprintf.
1 parent 7fafed0 commit 2113148

File tree

2 files changed

+39
-16
lines changed
  • libz-rs-sys-cdylib/src
  • test-libz-rs-sys/src

2 files changed

+39
-16
lines changed

libz-rs-sys-cdylib/src/gz.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct GzState {
5151
source: Source,
5252
want: usize, // requested buffer size, default is GZBUFSIZE
5353
input: *mut u8, // input buffer (double-sized when writing)
54-
in_size: usize, // size of *input
54+
in_size: usize, // usable size of input buffer (See [`gz_init`] for explanation.)
5555
output: *mut u8, // output buffer (double-sized when reading)
5656
out_size: usize, // size of *output
5757
direct: bool, // true in pass-through mode, false if processing gzip data
@@ -112,6 +112,22 @@ impl GzState {
112112
Ok((exclusive, cloexec))
113113
}
114114

115+
// Get the number of bytes allocated for the `self.input` buffer.
116+
fn in_capacity(&self) -> usize {
117+
match self.mode {
118+
GzMode::GZ_WRITE => self.want * 2,
119+
_ => self.want,
120+
}
121+
}
122+
123+
// Get the number of bytes allocated for the `self.output` buffer.
124+
fn out_capacity(&self) -> usize {
125+
match self.mode {
126+
GzMode::GZ_READ => self.want * 2,
127+
_ => self.want,
128+
}
129+
}
130+
115131
/// Compute the number of bytes of input buffered in `self`.
116132
///
117133
/// # Safety
@@ -509,14 +525,14 @@ unsafe fn free_buffers(state: &mut GzState) {
509525
if !state.input.is_null() {
510526
// Safety: state.input is always allocated using ALLOCATOR, and
511527
// its allocation size is stored in state.in_size.
512-
unsafe { ALLOCATOR.deallocate(state.input, state.in_size) };
528+
unsafe { ALLOCATOR.deallocate(state.input, state.in_capacity()) };
513529
state.input = ptr::null_mut();
514530
}
515531
state.in_size = 0;
516532
if !state.output.is_null() {
517-
// Safety: state.input is always allocated using ALLOCATOR, and
518-
// its allocation size is stored in state.in_size.
519-
unsafe { ALLOCATOR.deallocate(state.output, state.out_size) };
533+
// Safety: state.output is always allocated using ALLOCATOR, and
534+
// its allocation size is stored in state.out_size.
535+
unsafe { ALLOCATOR.deallocate(state.output, state.out_capacity()) };
520536
state.output = ptr::null_mut();
521537
}
522538
state.out_size = 0;
@@ -1185,17 +1201,19 @@ fn gz_skip(state: &mut GzState, mut len: i64) -> Result<(), ()> {
11851201
unsafe fn gz_look(state: &mut GzState) -> Result<(), ()> {
11861202
// Allocate buffers if needed.
11871203
if state.input.is_null() {
1188-
state.in_size = state.want;
1189-
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(state.in_size) else {
1204+
let capacity = state.in_capacity();
1205+
state.in_size = capacity;
1206+
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
11901207
// Safety: The caller confirmed the validity of state.
11911208
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };
11921209
return Err(());
11931210
};
11941211
state.input = input.as_ptr();
11951212

11961213
if state.output.is_null() {
1197-
state.out_size = state.want * 2;
1198-
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(state.out_size) else {
1214+
let capacity = state.out_capacity();
1215+
state.out_size = capacity;
1216+
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
11991217
// Safety: The caller confirmed the validity of state, and free_buffers checks
12001218
// for null input and output pointers internally.
12011219
unsafe { free_buffers(state) };
@@ -1705,9 +1723,14 @@ fn gz_zero(state: &mut GzState, mut len: usize) -> Result<(), ()> {
17051723
// - `Ok` on success.
17061724
// - `Err` on error.
17071725
fn gz_init(state: &mut GzState) -> Result<(), ()> {
1708-
// Allocate input buffer (double size for gzprintf).
1709-
state.in_size = state.want * 2;
1710-
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(state.in_size) else {
1726+
// Allocate input buffer.
1727+
// The buffer is twice as big as state.want, but we set in_size to half the
1728+
// buffer size (i.e. state.in_size == state.want). The reason for this is to
1729+
// ensure that we always have state.want bytes available for exclusive use
1730+
// by gzprintf.
1731+
let capacity = state.in_capacity();
1732+
state.in_size = capacity / 2;
1733+
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
17111734
// Safety: The caller confirmed the validity of state.
17121735
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };
17131736
return Err(());
@@ -1718,8 +1741,9 @@ fn gz_init(state: &mut GzState) -> Result<(), ()> {
17181741
// Only need output buffer and deflate state if compressing.
17191742
if !state.direct {
17201743
// Allocate output buffer.
1721-
state.out_size = state.want;
1722-
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(state.out_size) else {
1744+
let capacity = state.out_capacity();
1745+
state.out_size = capacity;
1746+
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
17231747
unsafe { free_buffers(state) };
17241748
// Safety: The caller confirmed the validity of state.
17251749
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };

test-libz-rs-sys/src/gz.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,7 @@ fn gzputc_error() {
993993
let file = unsafe { gzdopen(-2, CString::new("wT").unwrap().as_ptr()) };
994994
const BUF_SIZE: usize = 10;
995995
assert_eq!(unsafe { gzbuffer(file, BUF_SIZE as _) }, 0);
996-
// In write mode, the internal input buffer is 2x the size specified via gzbuffer.
997-
for _ in 0..BUF_SIZE * 2 {
996+
for _ in 0..BUF_SIZE {
998997
assert_eq!(unsafe { gzputc(file, 1) }, 1);
999998
}
1000999
assert_eq!(unsafe { gzputc(file, 1) }, -1);

0 commit comments

Comments
 (0)