Skip to content

Inflater::total_out() overflows 32-bit integer boundary on Windows despite being u64 #472

@chenxiaolong

Description

@chenxiaolong

When unpacking a large gzipped file on Windows, total_out "overflows" after decompressing past 4 GiB.

For example, if I create a file with compressed zeros (on Linux) like this:

head -c $((5 * 1024 * 1024 * 1024)) /dev/zero | gzip -1 > zeros.gz

and then try to decompress that on Windows with the code below, then flate2 panics due to subtraction overflow on:

https://github.com/rust-lang/flate2-rs/blob/9d3582860d3666a2771ea8933b396fda57560ec8/src/ffi/zlib_rs.rs#L109

Although the panic is in flate2, I think the issue is in zlib-rs. I tried adding a short log line there and it shows total_out is wrapping over a 32-bit boundary, going from 4294959496 to 392.

It seems that total_out has type z_size:

pub(crate) total_out: crate::c_api::z_size,

and z_size is an alias for c_ulong:

pub(crate) type z_size = c_ulong;

but c_ulong is a 32-bit integer on Windows systems, even if the host is 64-bit. Would it make sense for total_out (and maybe total_in?) to be a type that's always 64 bits?

Thanks!


Reproducer:

use std::{env, fs::File, io::Read, path::PathBuf};

use flate2::read::GzDecoder;

fn main() {
    let input_path = PathBuf::from(env::args_os().skip(1).next().unwrap());

    let file = File::open(&input_path).unwrap();
    let mut decoder = GzDecoder::new(file);
    let mut buf = [0u8; 8192];

    loop {
        let n = decoder.read(&mut buf).unwrap();
        if n == 0 {
            break;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions