Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ jobs:
- name: target
run: "rustc -vV | sed -n 's|host: ||p'"
- name: Install cargo-nextest
uses: taiki-e/install-action@56ab7930c591507f833cbaed864d201386d518a8
uses: taiki-e/install-action@a48a50298f98c47e46a957ae6f82c44cc4878e42 # v2.49.47
with:
tool: cargo-nextest
- name: cargo build
Expand Down Expand Up @@ -180,7 +180,7 @@ jobs:
components: clippy, rustfmt
targets: ${{matrix.target}}
- name: Rust cache
uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
shared-key: "stable-${{matrix.target}}"

Expand Down Expand Up @@ -448,7 +448,7 @@ jobs:
- name: target
run: "rustc -vV | sed -n 's|host: ||p'"
- name: Install cargo-nextest
uses: taiki-e/install-action@56ab7930c591507f833cbaed864d201386d518a8
uses: taiki-e/install-action@a48a50298f98c47e46a957ae6f82c44cc4878e42 # v2.49.47
with:
tool: cargo-nextest
- name: Download wasi-sdk
Expand Down Expand Up @@ -490,7 +490,7 @@ jobs:
sudo apt-get install gcc-mingw-w64-x86-64
x86_64-w64-mingw32-gcc --help
- name: Install cargo-nextest
uses: taiki-e/install-action@56ab7930c591507f833cbaed864d201386d518a8
uses: taiki-e/install-action@a48a50298f98c47e46a957ae6f82c44cc4878e42 # v2.49.47
with:
tool: cargo-nextest
- name: Test public C api with NULL arguments
Expand Down
52 changes: 38 additions & 14 deletions libz-rs-sys-cdylib/src/gz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct GzState {
source: Source,
want: usize, // requested buffer size, default is GZBUFSIZE
input: *mut u8, // input buffer (double-sized when writing)
in_size: usize, // size of *input
in_size: usize, // usable size of input buffer (See [`gz_init`] for explanation.)
output: *mut u8, // output buffer (double-sized when reading)
out_size: usize, // size of *output
direct: bool, // true in pass-through mode, false if processing gzip data
Expand Down Expand Up @@ -112,6 +112,22 @@ impl GzState {
Ok((exclusive, cloexec))
}

// Get the number of bytes allocated for the `self.input` buffer.
fn in_capacity(&self) -> usize {
match self.mode {
GzMode::GZ_WRITE => self.want * 2,
_ => self.want,
}
}

// Get the number of bytes allocated for the `self.output` buffer.
fn out_capacity(&self) -> usize {
match self.mode {
GzMode::GZ_READ => self.want * 2,
_ => self.want,
}
}

/// Compute the number of bytes of input buffered in `self`.
///
/// # Safety
Expand Down Expand Up @@ -509,14 +525,14 @@ unsafe fn free_buffers(state: &mut GzState) {
if !state.input.is_null() {
// Safety: state.input is always allocated using ALLOCATOR, and
// its allocation size is stored in state.in_size.
unsafe { ALLOCATOR.deallocate(state.input, state.in_size) };
unsafe { ALLOCATOR.deallocate(state.input, state.in_capacity()) };
state.input = ptr::null_mut();
}
state.in_size = 0;
if !state.output.is_null() {
// Safety: state.input is always allocated using ALLOCATOR, and
// its allocation size is stored in state.in_size.
unsafe { ALLOCATOR.deallocate(state.output, state.out_size) };
// Safety: state.output is always allocated using ALLOCATOR, and
// its allocation size is stored in state.out_size.
unsafe { ALLOCATOR.deallocate(state.output, state.out_capacity()) };
state.output = ptr::null_mut();
}
state.out_size = 0;
Expand Down Expand Up @@ -1185,17 +1201,19 @@ fn gz_skip(state: &mut GzState, mut len: i64) -> Result<(), ()> {
unsafe fn gz_look(state: &mut GzState) -> Result<(), ()> {
// Allocate buffers if needed.
if state.input.is_null() {
state.in_size = state.want;
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(state.in_size) else {
let capacity = state.in_capacity();
state.in_size = capacity;
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
// Safety: The caller confirmed the validity of state.
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };
return Err(());
};
state.input = input.as_ptr();

if state.output.is_null() {
state.out_size = state.want * 2;
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(state.out_size) else {
let capacity = state.out_capacity();
state.out_size = capacity;
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
// Safety: The caller confirmed the validity of state, and free_buffers checks
// for null input and output pointers internally.
unsafe { free_buffers(state) };
Expand Down Expand Up @@ -1705,9 +1723,14 @@ fn gz_zero(state: &mut GzState, mut len: usize) -> Result<(), ()> {
// - `Ok` on success.
// - `Err` on error.
fn gz_init(state: &mut GzState) -> Result<(), ()> {
// Allocate input buffer (double size for gzprintf).
state.in_size = state.want * 2;
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(state.in_size) else {
// Allocate input buffer.
// The buffer is twice as big as state.want, but we set in_size to half the
// buffer size (i.e. state.in_size == state.want). The reason for this is to
// ensure that we always have state.want bytes available for exclusive use
// by gzprintf.
let capacity = state.in_capacity();
state.in_size = capacity / 2;
let Some(input) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
// Safety: The caller confirmed the validity of state.
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };
return Err(());
Expand All @@ -1718,8 +1741,9 @@ fn gz_init(state: &mut GzState) -> Result<(), ()> {
// Only need output buffer and deflate state if compressing.
if !state.direct {
// Allocate output buffer.
state.out_size = state.want;
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(state.out_size) else {
let capacity = state.out_capacity();
state.out_size = capacity;
let Some(output) = ALLOCATOR.allocate_slice_raw::<u8>(capacity) else {
unsafe { free_buffers(state) };
// Safety: The caller confirmed the validity of state.
unsafe { gz_error(state, Some((Z_MEM_ERROR, "out of memory"))) };
Expand Down
3 changes: 1 addition & 2 deletions test-libz-rs-sys/src/gz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,8 +993,7 @@ fn gzputc_error() {
let file = unsafe { gzdopen(-2, CString::new("wT").unwrap().as_ptr()) };
const BUF_SIZE: usize = 10;
assert_eq!(unsafe { gzbuffer(file, BUF_SIZE as _) }, 0);
// In write mode, the internal input buffer is 2x the size specified via gzbuffer.
for _ in 0..BUF_SIZE * 2 {
for _ in 0..BUF_SIZE {
assert_eq!(unsafe { gzputc(file, 1) }, 1);
}
assert_eq!(unsafe { gzputc(file, 1) }, -1);
Expand Down
Loading