diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 51199120..b1899284 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,30 +64,30 @@ jobs: cp Cargo.lock.msrv Cargo.lock - run: | cargo test - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys - run: | cargo test --features parallel - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys - run: | cargo test --no-default-features --features xz-sys - cargo clean -p liblzma -p xz-sys + cargo clean -p xz -p xz-sys - run: | cargo test --no-default-features --features liblzma-sys - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys # thin-lto and fat-lto feature required use clang as a linker, but linux default linker is gcc. so exclude thin-lto and fat-lto. - run: | cargo test --no-default-features --features liblzma-sys,parallel,static - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys if: ${{ startsWith(matrix.os, 'ubuntu') }} - run: | cargo test --test sys_equivalence - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys if: ${{ !startsWith(matrix.os, 'ubuntu') }} - run: | cargo run --manifest-path systest/Cargo.toml --no-default-features --features xz-sys cargo clean -p xz-sys cargo run --manifest-path systest/Cargo.toml --no-default-features --features liblzma-sys - cargo clean -p liblzma -p liblzma-sys + cargo clean -p xz -p liblzma-sys if: matrix.static == 'yes' - run: cargo run --manifest-path systest/Cargo.toml --no-default-features --features liblzma-sys,bindgen if: matrix.static == 'yes' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6098cfb1..5fe0a89e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,8 +20,8 @@ jobs: working-directory: liblzma-sys env: CARGO_REGISTRY_TOKEN: "${{ secrets.CRATES_IO_API_KEY }}" - - if: "!startsWith(github.ref, 'refs/tags/liblzma-sys') && startsWith(github.ref, 'refs/tags/liblzma')" - name: Publish liblzma crate + - if: "!startsWith(github.ref, 'refs/tags/liblzma-sys') && !startsWith(github.ref, 'refs/tags/xz-sys') && startsWith(github.ref, 'refs/tags/xz')" + name: Publish xz crate run: cargo publish working-directory: . env: diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv index d6bc6b88..c555fff4 100644 --- a/Cargo.lock.msrv +++ b/Cargo.lock.msrv @@ -396,23 +396,6 @@ version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" -[[package]] -name = "liblzma" -version = "0.4.6" -dependencies = [ - "criterion", - "getrandom 0.2.17", - "liblzma-sys", - "log", - "num_cpus", - "quickcheck", - "rand", - "regex", - "wasm-bindgen-test", - "xz-core", - "xz-sys", -] - [[package]] name = "liblzma-sys" version = "0.4.6" @@ -970,6 +953,23 @@ version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" +[[package]] +name = "xz" +version = "0.4.6" +dependencies = [ + "criterion", + "getrandom 0.2.17", + "liblzma-sys", + "log", + "num_cpus", + "quickcheck", + "rand", + "regex", + "wasm-bindgen-test", + "xz-core", + "xz-sys", +] + [[package]] name = "xz-core" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e0ef0d70..6f3bcdea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] -name = "liblzma" +name = "xz" version = "0.4.6" authors = ["Alex Crichton ", "Portable-Network-Archive Developers"] license = "MIT OR Apache-2.0" readme = "README.md" keywords = ["lzma", "xz", "encoding", "wasm"] -repository = "https://github.com/portable-network-archive/liblzma-rs" -homepage = "https://github.com/portable-network-archive/liblzma-rs" +repository = "https://github.com/youknowone/xz-rs" +homepage = "https://github.com/youknowone/xz-rs" description = """ -Rust bindings to liblzma providing Read/Write streams as well as low-level +Pure Rust xz library providing Read/Write streams as well as low-level in-memory encoding/decoding. forked from xz2. """ categories = ["compression", "api-bindings"] @@ -41,8 +41,8 @@ required-features = ["bench"] getrandom = { version = "0.2", features = ["js"] } [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] -xz-sys = { path = "xz-sys" } -liblzma-sys = { path = "liblzma-sys" } +xz-sys = { path = "xz-sys", features = ["parallel"] } +liblzma-sys = { path = "liblzma-sys", features = ["parallel"] } [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/README.md b/README.md index 4ec14149..1457cc82 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,16 @@ -# liblzma +# xz -[![CI](https://github.com/Portable-Network-Archive/liblzma-rs/actions/workflows/main.yml/badge.svg)](https://github.com/Portable-Network-Archive/liblzma-rs/actions/workflows/main.yml) +[![CI](https://github.com/youknowone/xz-rs/actions/workflows/main.yml/badge.svg)](https://github.com/youknowone/xz-rs/actions/workflows/main.yml) [![Crates.io][crates-badge]][crates-url] -[crates-badge]: https://img.shields.io/crates/v/liblzma.svg -[crates-url]: https://crates.io/crates/liblzma +[crates-badge]: https://img.shields.io/crates/v/xz.svg +[crates-url]: https://crates.io/crates/xz -[Documentation](https://docs.rs/liblzma) +[Documentation](https://docs.rs/xz) -Bindings to the liblzma implementation in Rust, also provides types to -read/write xz streams. +Pure Rust xz2/liblzma-compatible crates for reading and writing xz streams. -**This crate is forked from [xz2](https://crates.io/crates/xz2) and `liblzma = "0.1.x"` is fully compatible with `xz2 = "0.1.7"`,** +**This crate is forked from [xz2](https://crates.io/crates/xz2) and `xz = "0.1.x"` is fully compatible with `xz2 = "0.1.7"`,** so you can migrate simply. ## Migrate from xz2 @@ -20,13 +19,13 @@ so you can migrate simply. # Cargo.toml [dependencies] -xz2 = "0.1.7" -+liblzma = "0.1.7" ++xz = "0.1.7" ``` ```diff // *.rs -use xz2; -+use liblzma; ++use xz; ``` ## Version 0.2.x breaking changes @@ -45,14 +44,28 @@ so you can migrate simply. - XZ upgraded to 5.8 - Dropped `tokio` support (If you need async I/O, use [`async-compression`](https://github.com/Nullus157/async-compression) crate with `lzma` feature flag) -## Backend selection +## Crates and backend selection -The default build uses the pure Rust backend via `xz-sys`. +This repository contains three pure Rust crates: -Use the original C backend only when you explicitly opt into it: +- `xz-core` is a direct port of the xz C library internals. +- `xz-sys` is a C ABI compatibility layer backed by `xz-core`. It is intended + to be compatible with `xz2-sys` and `liblzma-sys`, and should be easy to link + from C as a liblzma-compatible library. +- `xz` is the high-level Rust interface intended as a replacement for `xz2` + and `liblzma`. + +The high-level `xz` crate defaults to the pure Rust `xz-core` backend. You can +disable default features and choose exactly one backend explicitly: + +- `xz-core` calls the pure Rust core directly. +- `xz-sys` calls the pure Rust core through the liblzma-compatible C ABI layer. +- `liblzma-sys` calls the original C liblzma implementation. + +To use the original C backend: ```toml -liblzma = { version = "0.4", default-features = false, features = ["liblzma-sys"] } +xz = { version = "0.4", default-features = false, features = ["liblzma-sys"] } ``` ## License @@ -69,5 +82,5 @@ at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in liblzma by you, as defined in the Apache-2.0 license, shall be +for inclusion in xz by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/docs/performance-workflow.md b/docs/performance-workflow.md index 965193e6..57e6338c 100644 --- a/docs/performance-workflow.md +++ b/docs/performance-workflow.md @@ -4,9 +4,9 @@ This repository now has a repeatable loop for backend comparison, profiling, and Important: the C and Rust sys backends must never be linked into the same process when comparing performance. Both export the same `lzma_*` symbols, so shared-process comparisons can silently resolve to the wrong implementation. -The root crate now has three backend modes: +The root crate has three backend modes: -- `xz-core`: direct Rust ABI calls into the pure Rust port +- `xz-core`: direct Rust ABI calls into the pure Rust port. This is the default. - `xz-sys`: C ABI calls into the pure Rust port through the `xz-sys` shell - `liblzma-sys`: C ABI calls into vendored C `liblzma` @@ -24,6 +24,8 @@ cargo test cargo test --no-default-features --features xz-sys cargo test --no-default-features --features liblzma-sys cargo test --test sys_equivalence +cargo run --manifest-path systest/Cargo.toml --no-default-features --features xz-sys +cargo run --manifest-path systest/Cargo.toml --no-default-features --features liblzma-sys ``` ## 2. Compare the full test suite @@ -80,7 +82,7 @@ still needs millions of in-process iterations; start around `--iters 2000000 --w comparison scripts also pre-generate its compressed input so the one-time encode setup doesn't hide the `uncompressed_size()` path. -There is still a criterion bench in [`benches/backend_comparison.rs`](../benches/backend_comparison.rs), but it now measures one backend per run. Use it only with exactly one backend feature enabled. +There is still a criterion bench in [`benches/backend_comparison.rs`](../benches/backend_comparison.rs), but it now measures one backend per run. Use it with exactly one backend feature enabled. For high-level API regressions, compare the root crate against the upstream XZ corpus: @@ -92,7 +94,7 @@ scripts/compare_api_workloads.sh qc --mode both --cases 128 --max-size 4096 --it scripts/compare_api_workloads.sh bufread-trailing --mode both --input-size 1024 --trailing-size 123 --iters 1000 --warmup 100 ``` -This uses [`examples/standard_files_probe.rs`](../examples/standard_files_probe.rs), which mirrors the `tests/xz.rs` `standard_files` path and writes reports to: +This uses [`examples/standard_files_probe.rs`](../examples/standard_files_probe.rs), which mirrors the `tests/standard_files.rs` `standard_files` path and writes reports to: - `target/perf-results/api-standard-files.json` - `target/perf-results/api-standard-files.md` diff --git a/examples/bufread_trailing_probe.rs b/examples/bufread_trailing_probe.rs index 25957ffd..b3deed63 100644 --- a/examples/bufread_trailing_probe.rs +++ b/examples/bufread_trailing_probe.rs @@ -2,7 +2,7 @@ use std::env; use std::io::Read; use std::time::{Duration, Instant}; -use liblzma::bufread; +use xz::bufread; #[cfg(feature = "xz-core")] const BACKEND_NAME: &str = "xz-core"; diff --git a/examples/qc_probe.rs b/examples/qc_probe.rs index 985ab15a..75765ca6 100644 --- a/examples/qc_probe.rs +++ b/examples/qc_probe.rs @@ -2,8 +2,8 @@ use std::env; use std::io::{Read, Write}; use std::time::{Duration, Instant}; -use liblzma::read; -use liblzma::write; +use xz::read; +use xz::write; #[cfg(feature = "xz-core")] const BACKEND_NAME: &str = "xz-core"; diff --git a/examples/standard_files_probe.rs b/examples/standard_files_probe.rs index 8f85821b..1a4f9735 100644 --- a/examples/standard_files_probe.rs +++ b/examples/standard_files_probe.rs @@ -4,9 +4,9 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::{Duration, Instant}; -use liblzma::read; -use liblzma::stream; -use liblzma::write; +use xz::read; +use xz::stream; +use xz::write; #[cfg(feature = "xz-core")] const BACKEND_NAME: &str = "xz-core"; diff --git a/scripts/compare_all_trimmed.sh b/scripts/compare_all_trimmed.sh index 55b2d990..c59cb54a 100755 --- a/scripts/compare_all_trimmed.sh +++ b/scripts/compare_all_trimmed.sh @@ -106,7 +106,7 @@ record_pair() { echo "prebuilding root test binaries..." env CARGO_TARGET_DIR="$RUST_TARGET" \ - cargo test -p liblzma --release --no-default-features --features xz-core --lib --tests --no-run >/dev/null + cargo test -p xz --release --no-default-features --features xz-core --lib --tests --no-run >/dev/null env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$C_TARGET" \ cargo test --release --no-default-features --features liblzma-sys --lib --tests --no-run >/dev/null diff --git a/scripts/compare_backends.sh b/scripts/compare_backends.sh index b4b08876..184d4b4f 100755 --- a/scripts/compare_backends.sh +++ b/scripts/compare_backends.sh @@ -70,7 +70,7 @@ SYSTEST_RUST_CMD="env CARGO_TARGET_DIR=$SYSTEST_RUST_TARGET cargo test -p systes SYSTEST_C_CMD="env LZMA_API_STATIC=1 CARGO_TARGET_DIR=$SYSTEST_C_TARGET cargo test -p systest --release --no-default-features --features liblzma-sys -- --test-threads=1" echo "prebuilding root test binaries..." -env CARGO_TARGET_DIR="$ROOT_RUST_TARGET" cargo test -p liblzma --release --no-default-features --features xz-core --no-run >/dev/null +env CARGO_TARGET_DIR="$ROOT_RUST_TARGET" cargo test -p xz --release --no-default-features --features xz-core --no-run >/dev/null env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$ROOT_C_TARGET" cargo test --release --no-default-features --features liblzma-sys --no-run >/dev/null hyperfine \ diff --git a/scripts/inspect_codegen.sh b/scripts/inspect_codegen.sh index d3722236..7ba5b6fd 100755 --- a/scripts/inspect_codegen.sh +++ b/scripts/inspect_codegen.sh @@ -6,7 +6,7 @@ print_usage() { Usage: scripts/inspect_codegen.sh [options] Options: - --package Cargo package to inspect (default: xz) + --package Cargo package to inspect (default: xz-core) --format Output format for cargo-asm (default: asm) --features Cargo feature list passed to cargo-asm --target-dir Cargo target dir (default: target/codegen) diff --git a/scripts/run_root_test_bins.sh b/scripts/run_root_test_bins.sh index b831b195..6576ce01 100755 --- a/scripts/run_root_test_bins.sh +++ b/scripts/run_root_test_bins.sh @@ -23,10 +23,10 @@ fi for ((repeat = 0; repeat < REPEATS; repeat++)); do for prefix in \ - "liblzma-" \ + "xz-" \ "drop_incomplete-" \ "sys_equivalence-" \ - "xz-" + "standard_files-" do BIN="" while IFS= read -r candidate; do @@ -40,7 +40,7 @@ for ((repeat = 0; repeat < REPEATS; repeat++)); do exit 1 fi ARGS=(--test-threads=1) - if [[ "$prefix" == "liblzma-" ]]; then + if [[ "$prefix" == "xz-" ]]; then # QuickCheck-based tests use a fresh RNG per process, so backend-to-backend # wall-clock comparisons on them are not stable. Cover those paths with # deterministic focused probes instead. diff --git a/src/lib.rs b/src/lib.rs index b4c357a6..652d1c06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,15 @@ //! LZMA/XZ encoding and decoding streams //! -//! This library is a binding to liblzma currently to provide LZMA and xz -//! encoding/decoding streams. I/O streams are provided in the `read`, `write`, +//! This library provides LZMA and xz encoding/decoding streams. +//! I/O streams are provided in the `read`, `write`, //! and `bufread` modules (same types, different bounds). Raw in-memory //! compression/decompression is provided via the `stream` module and contains -//! many of the raw APIs in liblzma. +//! many of the raw APIs exposed by the selected backend. //! //! # Examples //! //! ```no_run -//! use liblzma::read::{XzDecoder, XzEncoder}; +//! use xz::read::{XzDecoder, XzEncoder}; //! use std::io::prelude::*; //! //! // Round trip some bytes from a byte source, into a compressor, into a @@ -25,10 +25,10 @@ //! # Static linking //! //! You can enable static-linking using the `static` feature, so that the XZ -//! library is not required at runtime: +//! library is not required at runtime when using the `liblzma-sys` backend: //! //! ```toml -//! liblzma = { version = "0.4", features = ["static"] } +//! xz = { version = "0.4", default-features = false, features = ["liblzma-sys", "static"] } //! ``` //! //! # Multithreading @@ -37,7 +37,7 @@ //! feature of this crate: //! //! ```toml -//! liblzma = { version = "0.4", features = ["parallel"] } +//! xz = { version = "0.4", features = ["parallel"] } //! ``` //! //! # Async I/O @@ -49,7 +49,7 @@ //! async-compression = { version = "0.4", features = ["lzma"] } //! ``` -#![doc(html_root_url = "https://docs.rs/liblzma/0.4.6")] +#![doc(html_root_url = "https://docs.rs/xz/0.4.6")] #![deny(missing_docs)] #[cfg(any( diff --git a/src/stream.rs b/src/stream.rs index cb9775b7..98157c92 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -761,7 +761,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -782,7 +782,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.delta_properties(&[0x00]).unwrap(); @@ -800,7 +800,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -821,7 +821,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.x86_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -839,7 +839,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -860,7 +860,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.powerpc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -878,7 +878,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -899,7 +899,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.ia64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -917,7 +917,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -938,7 +938,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.arm_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -956,7 +956,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -977,7 +977,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.arm64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -995,7 +995,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -1016,7 +1016,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.riscv_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -1034,7 +1034,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -1055,7 +1055,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.arm_thumb_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -1073,7 +1073,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); @@ -1094,7 +1094,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let mut filters = Filters::new(); /// filters.sparc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap(); @@ -1138,7 +1138,7 @@ impl Filters { /// /// # Examples /// ``` - /// use liblzma::stream::{Filters, LzmaOptions}; + /// use xz::stream::{Filters, LzmaOptions}; /// /// let dict_size = 0x40000; /// let mut opts = LzmaOptions::new_preset(6).unwrap(); diff --git a/tests/drop-incomplete.rs b/tests/drop-incomplete.rs index 8d1f75e7..c3a8d090 100644 --- a/tests/drop-incomplete.rs +++ b/tests/drop-incomplete.rs @@ -1,5 +1,5 @@ -use liblzma::write::XzDecoder; use std::io::prelude::*; +use xz::write::XzDecoder; // This is a XZ file generated by head -c10 /dev/urandom | xz -c const DATA: &'static [u8] = &[ diff --git a/tests/xz.rs b/tests/xz.rs deleted file mode 100644 index fdbbe7f9..00000000 --- a/tests/xz.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::fs::File; -use std::io::prelude::*; -use std::path::Path; - -use liblzma::read; -use liblzma::stream; -use liblzma::write; - -#[test] -fn standard_files() { - for file in Path::new("liblzma-sys/xz/tests/files").read_dir().unwrap() { - let file = file.unwrap(); - if file.path().extension().and_then(|s| s.to_str()) != Some("xz") { - continue; - } - - let filename = file.file_name().into_string().unwrap(); - - // This appears to be implementation-defined how it's handled - if filename.contains("unsupported-check") { - continue; - } - - println!("testing {:?}", file.path()); - let mut contents = Vec::new(); - File::open(&file.path()) - .unwrap() - .read_to_end(&mut contents) - .unwrap(); - if filename.starts_with("bad") || filename.starts_with("unsupported") { - test_bad(&contents); - } else { - test_good(&contents); - } - } -} - -fn test_good(data: &[u8]) { - let mut ret = Vec::new(); - read::XzDecoder::new_multi_decoder(data) - .read_to_end(&mut ret) - .unwrap(); - let mut w = write::XzDecoder::new_multi_decoder(ret); - w.write_all(data).unwrap(); - w.finish().unwrap(); -} - -fn test_bad(data: &[u8]) { - let mut ret = Vec::new(); - let stream = stream::Stream::new_stream_decoder(u64::MAX, stream::CONCATENATED).unwrap(); - let result = read::XzDecoder::new_stream(data, stream).read_to_end(&mut ret); - assert!(result.is_err(), "{result:?}"); - let mut w = write::XzDecoder::new(ret); - assert!(w.write_all(data).is_err() || w.finish().is_err()); -} - -fn assert_send_sync() {} - -#[test] -fn impls_send_and_sync() { - assert_send_sync::(); - assert_send_sync::>(); - assert_send_sync::>(); - assert_send_sync::>(); - assert_send_sync::>(); -} diff --git a/xz-core/Cargo.toml b/xz-core/Cargo.toml index 5e95c865..1f78f660 100644 --- a/xz-core/Cargo.toml +++ b/xz-core/Cargo.toml @@ -7,6 +7,7 @@ description = "Pure Rust implementation of liblzma (transpiled from C via c2rust [features] default = [] +custom_allocator = [] [dependencies] libc = "0.2" diff --git a/xz-core/src/alloc.rs b/xz-core/src/alloc.rs index 6e955431..37e070d5 100644 --- a/xz-core/src/alloc.rs +++ b/xz-core/src/alloc.rs @@ -1,219 +1,26 @@ -use crate::types::*; -use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; - -const RUST_ALLOC_ALIGN: usize = 16; - -#[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) -} - -fn rust_alloc_impl(size: usize, align: usize, zeroed: bool) -> *mut c_void { - let size = if size == 0 { 1 } else { size }; - 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 -} - -unsafe fn rust_free_impl(ptr: *mut c_void) { - if ptr.is_null() { - return; - } - let header_size = core::mem::size_of::(); - let user_ptr = ptr as *mut u8; - let header_ptr = user_ptr.sub(header_size) as *const RustAllocHeader; - let header = header_ptr.read(); - let base = user_ptr.sub(header.offset); - let layout = Layout::from_size_align_unchecked(header.total_size, header.align); - dealloc(base, layout); -} - -pub(crate) unsafe fn lzma_rust_alloc( - _opaque: *mut c_void, - nmemb: size_t, - size: size_t, -) -> *mut c_void { - 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) { - rust_free_impl(ptr); -} - -#[repr(transparent)] -struct StaticAllocator(lzma_allocator); - -unsafe impl Sync for StaticAllocator {} - -static RUST_ALLOCATOR: StaticAllocator = StaticAllocator(lzma_allocator { - alloc: Some(lzma_rust_alloc), - free: Some(lzma_rust_free), - opaque: core::ptr::null_mut(), -}); - -pub fn rust_allocator() -> lzma_allocator { - RUST_ALLOCATOR.0 -} - -pub(crate) fn rust_allocator_ptr() -> *const lzma_allocator { - &raw const RUST_ALLOCATOR.0 -} - -pub(crate) fn allocator_or_rust(allocator: *const lzma_allocator) -> *const lzma_allocator { - if allocator.is_null() { - rust_allocator_ptr() - } else { - allocator - } -} - -pub(crate) unsafe fn internal_alloc_bytes( - size: size_t, - allocator: *const lzma_allocator, -) -> *mut c_void { - let size = if size == 0 { 1 } else { size }; - let allocator = allocator_or_rust(allocator); - if let Some(alloc) = unsafe { (*allocator).alloc } { - return unsafe { alloc((*allocator).opaque, 1, size) }; - } - rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) -} - -pub(crate) unsafe fn internal_alloc_zeroed_bytes( - size: size_t, - allocator: *const lzma_allocator, -) -> *mut c_void { - let size = if size == 0 { 1 } else { size }; - let allocator = allocator_or_rust(allocator); - if let Some(alloc) = unsafe { (*allocator).alloc } { - let ptr = unsafe { alloc((*allocator).opaque, 1, size) }; - if !ptr.is_null() { - unsafe { core::ptr::write_bytes(ptr as *mut u8, 0, size) }; - } - return ptr; - } - rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, true) -} - -pub(crate) unsafe fn internal_alloc_object(allocator: *const lzma_allocator) -> *mut T { - if !allocator.is_null() - && let Some(alloc) = unsafe { (*allocator).alloc } - { - return unsafe { - 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 -} - -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(); - }; - if !allocator.is_null() - && let Some(alloc) = unsafe { (*allocator).alloc } - { - 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 -} - -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(); - }; - if !allocator.is_null() - && let Some(alloc) = unsafe { (*allocator).alloc } - { - let ptr = unsafe { alloc((*allocator).opaque, 1, size as size_t) as *mut T }; - if !ptr.is_null() { - unsafe { core::ptr::write_bytes(ptr as *mut u8, 0, size) }; - } - return ptr; - } - 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) { - if !allocator.is_null() - && let Some(free) = unsafe { (*allocator).free } - { - unsafe { free((*allocator).opaque, ptr) }; - return; - } - rust_free_impl(ptr); -} - -#[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 internal_object_allocation_respects_alignment() { - #[repr(align(32))] - struct Align32([u8; 32]); - - unsafe { - let ptr = internal_alloc_object::(core::ptr::null()); - assert!(!ptr.is_null()); - assert_eq!((ptr as usize) % core::mem::align_of::(), 0); - internal_free(ptr.cast(), core::ptr::null()); - } - } -} +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")] +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; +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, +}; diff --git a/xz-sys/src/c_allocator.rs b/xz-core/src/alloc/c.rs similarity index 57% rename from xz-sys/src/c_allocator.rs rename to xz-core/src/alloc/c.rs index 9ea6b07f..477310be 100644 --- a/xz-sys/src/c_allocator.rs +++ b/xz-core/src/alloc/c.rs @@ -1,13 +1,7 @@ -#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] -use libc::c_void; -#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] -use libc::size_t; +use crate::types::*; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -use std::os::raw::c_void; - -use crate::{lzma_allocator, lzma_stream}; #[cfg(all(target_family = "wasm", target_os = "unknown"))] const C_ALLOC_ALIGN: usize = 16; @@ -17,19 +11,34 @@ const C_ALLOC_HEADER_SIZE: usize = 16; #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] unsafe extern "C" { fn malloc(__size: size_t) -> *mut c_void; - #[allow(dead_code)] fn calloc(__count: size_t, __size: size_t) -> *mut c_void; fn free(__ptr: *mut c_void); } +#[repr(transparent)] +struct StaticAllocator(lzma_allocator); + +unsafe impl Sync for StaticAllocator {} + +static C_ALLOCATOR: StaticAllocator = StaticAllocator(lzma_allocator { + alloc: Some(lzma_c_alloc), + free: Some(lzma_c_free), + opaque: core::ptr::null_mut(), +}); + #[cfg(all(target_family = "wasm", target_os = "unknown"))] fn c_alloc_layout(size: usize) -> Option { let total_size = size.checked_add(C_ALLOC_HEADER_SIZE)?; Layout::from_size_align(total_size, C_ALLOC_ALIGN).ok() } +#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] +unsafe fn c_malloc(size: size_t) -> *mut c_void { + unsafe { malloc(size) } +} + #[cfg(all(target_family = "wasm", target_os = "unknown"))] -fn malloc(size: size_t) -> *mut c_void { +unsafe fn c_malloc(size: size_t) -> *mut c_void { let Some(layout) = c_alloc_layout(size as usize) else { return core::ptr::null_mut(); }; @@ -43,8 +52,13 @@ fn malloc(size: size_t) -> *mut c_void { } } +#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] +unsafe fn c_calloc(count: size_t, size: size_t) -> *mut c_void { + unsafe { calloc(count, size) } +} + #[cfg(all(target_family = "wasm", target_os = "unknown"))] -fn calloc(count: size_t, size: size_t) -> *mut c_void { +unsafe fn c_calloc(count: size_t, size: size_t) -> *mut c_void { let Some(size) = (count as usize).checked_mul(size as usize) else { return core::ptr::null_mut(); }; @@ -61,54 +75,66 @@ fn calloc(count: size_t, size: size_t) -> *mut c_void { } } +#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] +unsafe fn c_free(ptr: *mut c_void) { + unsafe { free(ptr) }; +} + #[cfg(all(target_family = "wasm", target_os = "unknown"))] -unsafe fn free(ptr: *mut c_void) { +unsafe fn c_free(ptr: *mut c_void) { if ptr.is_null() { return; } - let base = (ptr as *mut u8).sub(C_ALLOC_HEADER_SIZE); - let total_size = *(base as *const usize); - let layout = Layout::from_size_align_unchecked(total_size, C_ALLOC_ALIGN); - dealloc(base, layout); + let base = unsafe { (ptr as *mut u8).sub(C_ALLOC_HEADER_SIZE) }; + let total_size = unsafe { *(base as *const usize) }; + let layout = unsafe { Layout::from_size_align_unchecked(total_size, C_ALLOC_ALIGN) }; + unsafe { dealloc(base, layout) }; } -unsafe fn lzma_c_alloc(_opaque: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void { +pub unsafe fn lzma_c_alloc(_opaque: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void { let Some(size) = (nmemb as usize).checked_mul(size as usize) else { return core::ptr::null_mut(); }; let size = if size == 0 { 1 } else { size }; - malloc(size as size_t) + unsafe { c_malloc(size as size_t) } } -unsafe fn lzma_c_free(_opaque: *mut c_void, ptr: *mut c_void) { - free(ptr); +pub unsafe fn lzma_c_free(_opaque: *mut c_void, ptr: *mut c_void) { + unsafe { c_free(ptr) }; } -#[repr(transparent)] -struct StaticAllocator(lzma_allocator); +pub fn c_allocator() -> lzma_allocator { + C_ALLOCATOR.0 +} -unsafe impl Sync for StaticAllocator {} +pub fn c_allocator_ptr() -> *const lzma_allocator { + &raw const C_ALLOCATOR.0 +} -static C_ALLOCATOR: StaticAllocator = StaticAllocator(lzma_allocator { - alloc: Some(lzma_c_alloc), - free: Some(lzma_c_free), - opaque: core::ptr::null_mut(), -}); +pub(super) unsafe fn c_alloc_bytes(size: size_t) -> *mut c_void { + let size = if size == 0 { 1 } else { size }; + unsafe { c_malloc(size) } +} -fn c_allocator_ptr() -> *const lzma_allocator { - &raw const C_ALLOCATOR.0 +pub(super) unsafe fn c_alloc_zeroed_bytes(size: size_t) -> *mut c_void { + let size = if size == 0 { 1 } else { size }; + unsafe { c_calloc(1, size) } } -pub(crate) fn normalize_c_allocator(allocator: *const lzma_allocator) -> *const lzma_allocator { - if allocator.is_null() { - c_allocator_ptr() - } else { - allocator - } +pub(super) unsafe fn c_free_ptr(ptr: *mut c_void) { + unsafe { c_free(ptr) }; } -pub(crate) unsafe fn normalize_c_stream_allocator(strm: *mut lzma_stream) { - if !strm.is_null() && (*strm).allocator.is_null() { - (*strm).allocator = c_allocator_ptr(); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn c_allocator_round_trip() { + unsafe { + let ptr = lzma_c_alloc(core::ptr::null_mut(), 4, 8); + assert!(!ptr.is_null()); + lzma_c_free(core::ptr::null_mut(), ptr); + } } } diff --git a/xz-core/src/alloc/custom.rs b/xz-core/src/alloc/custom.rs new file mode 100644 index 00000000..38e8c5aa --- /dev/null +++ b/xz-core/src/alloc/custom.rs @@ -0,0 +1,125 @@ +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}; + +fn c_size(size: size_t) -> size_t { + if size == 0 { 1 } else { size } +} + +pub(crate) fn allocator_or_rust(allocator: *const lzma_allocator) -> *const lzma_allocator { + if allocator.is_null() { + rust_allocator_ptr() + } else { + allocator + } +} + +pub fn allocator_or_c(allocator: *const lzma_allocator) -> *const lzma_allocator { + if allocator.is_null() { + c_allocator_ptr() + } else { + allocator + } +} + +pub unsafe fn lzma_alloc(size: size_t, allocator: *const lzma_allocator) -> *mut c_void { + let size = c_size(size); + if !allocator.is_null() + && let Some(alloc) = unsafe { (*allocator).alloc } + { + return unsafe { alloc((*allocator).opaque, 1, size) }; + } + unsafe { c_alloc_bytes(size) } +} + +pub unsafe fn lzma_alloc_zero(size: size_t, allocator: *const lzma_allocator) -> *mut c_void { + let size = c_size(size); + if !allocator.is_null() + && let Some(alloc) = unsafe { (*allocator).alloc } + { + let ptr = unsafe { alloc((*allocator).opaque, 1, size) }; + if !ptr.is_null() { + unsafe { core::ptr::write_bytes(ptr as *mut u8, 0, size) }; + } + return ptr; + } + unsafe { c_alloc_zeroed_bytes(size) } +} + +pub unsafe fn lzma_free(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 { c_free_ptr(ptr) }; +} + +pub(crate) unsafe fn internal_alloc_bytes( + size: size_t, + allocator: *const lzma_allocator, +) -> *mut c_void { + let size = c_size(size); + let allocator = allocator_or_rust(allocator); + if let Some(alloc) = unsafe { (*allocator).alloc } { + return unsafe { alloc((*allocator).opaque, 1, size) }; + } + rust_alloc_impl(size as usize, RUST_ALLOC_ALIGN, false) +} + +pub(crate) unsafe fn internal_alloc_object(allocator: *const lzma_allocator) -> *mut T { + if !allocator.is_null() + && let Some(alloc) = unsafe { (*allocator).alloc } + { + return unsafe { + 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 +} + +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(); + }; + if !allocator.is_null() + && let Some(alloc) = unsafe { (*allocator).alloc } + { + 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 +} + +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(); + }; + if !allocator.is_null() + && let Some(alloc) = unsafe { (*allocator).alloc } + { + let ptr = unsafe { alloc((*allocator).opaque, 1, size as size_t) as *mut T }; + if !ptr.is_null() { + unsafe { core::ptr::write_bytes(ptr as *mut u8, 0, size) }; + } + return ptr; + } + 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) { + if !allocator.is_null() + && let Some(free) = unsafe { (*allocator).free } + { + unsafe { free((*allocator).opaque, ptr) }; + return; + } + unsafe { rust_free_ptr(ptr) }; +} diff --git a/xz-core/src/alloc/rust.rs b/xz-core/src/alloc/rust.rs new file mode 100644 index 00000000..e6fcafb0 --- /dev/null +++ b/xz-core/src/alloc/rust.rs @@ -0,0 +1,147 @@ +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); + +unsafe impl Sync for StaticAllocator {} + +static RUST_ALLOCATOR: StaticAllocator = StaticAllocator(lzma_allocator { + alloc: Some(lzma_rust_alloc), + free: Some(lzma_rust_free), + 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( + _opaque: *mut c_void, + nmemb: size_t, + size: size_t, +) -> *mut c_void { + 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) +} + +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 fn rust_allocator() -> lzma_allocator { + RUST_ALLOCATOR.0 +} + +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 new file mode 100644 index 00000000..51f15276 --- /dev/null +++ b/xz-core/src/alloc/rust_only.rs @@ -0,0 +1,58 @@ +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 afd4e09f..0ea96acd 100644 --- a/xz-core/src/common/alone_decoder.rs +++ b/xz-core/src/common/alone_decoder.rs @@ -243,7 +243,7 @@ pub unsafe fn lzma_alone_decoder(strm: *mut lzma_stream, memlimit: u64) -> lzma_ } let ret__0: lzma_ret = lzma_alone_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), memlimit, false, ); diff --git a/xz-core/src/common/alone_encoder.rs b/xz-core/src/common/alone_encoder.rs index 81e0f5a8..10071af8 100644 --- a/xz-core/src/common/alone_encoder.rs +++ b/xz-core/src/common/alone_encoder.rs @@ -210,7 +210,7 @@ pub unsafe fn lzma_alone_encoder( } let ret: lzma_ret = alone_encoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), options, ); if ret != LZMA_OK { diff --git a/xz-core/src/common/auto_decoder.rs b/xz-core/src/common/auto_decoder.rs index 6cc30ff5..57954212 100644 --- a/xz-core/src/common/auto_decoder.rs +++ b/xz-core/src/common/auto_decoder.rs @@ -108,7 +108,7 @@ pub unsafe fn lzma_auto_decoder(strm: *mut lzma_stream, memlimit: u64, flags: u3 } let ret: lzma_ret = auto_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), memlimit, flags, ); diff --git a/xz-core/src/common/block_decoder.rs b/xz-core/src/common/block_decoder.rs index bebd5548..8ca3b39b 100644 --- a/xz-core/src/common/block_decoder.rs +++ b/xz-core/src/common/block_decoder.rs @@ -262,7 +262,7 @@ pub unsafe fn lzma_block_decoder(strm: *mut lzma_stream, block: *mut lzma_block) } let ret__0: lzma_ret = lzma_block_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), block, ); if ret__0 != LZMA_OK { diff --git a/xz-core/src/common/block_encoder.rs b/xz-core/src/common/block_encoder.rs index e72403d0..2965d099 100644 --- a/xz-core/src/common/block_encoder.rs +++ b/xz-core/src/common/block_encoder.rs @@ -229,7 +229,7 @@ pub unsafe fn lzma_block_encoder(strm: *mut lzma_stream, block: *mut lzma_block) } let ret__0: lzma_ret = lzma_block_encoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), block, ); if ret__0 != LZMA_OK { diff --git a/xz-core/src/common/common.rs b/xz-core/src/common/common.rs index 446769dc..86e8ff7c 100644 --- a/xz-core/src/common/common.rs +++ b/xz-core/src/common/common.rs @@ -1,69 +1,5 @@ -use crate::alloc::allocator_or_rust; +pub use crate::alloc::{lzma_alloc, lzma_alloc_zero, lzma_free}; use crate::types::*; -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; - -#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] -unsafe extern "C" { - fn malloc(__size: size_t) -> *mut c_void; - fn calloc(__count: size_t, __size: size_t) -> *mut c_void; - fn free(_: *mut c_void); -} - -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -const LZMA_ALLOC_ALIGN: usize = 16; -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -const LZMA_ALLOC_HEADER_SIZE: usize = 16; - -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -fn rust_alloc_layout(size: usize) -> Option { - let total_size = size.checked_add(LZMA_ALLOC_HEADER_SIZE)?; - Layout::from_size_align(total_size, LZMA_ALLOC_ALIGN).ok() -} - -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -fn malloc(size: size_t) -> *mut c_void { - let Some(layout) = rust_alloc_layout(size as usize) else { - return core::ptr::null_mut(); - }; - let base = unsafe { alloc(layout) }; - if base.is_null() { - return core::ptr::null_mut(); - } - unsafe { - *(base as *mut usize) = layout.size(); - base.add(LZMA_ALLOC_HEADER_SIZE) as *mut c_void - } -} - -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -fn calloc(count: size_t, size: size_t) -> *mut c_void { - let Some(size) = (count as usize).checked_mul(size as usize) else { - return core::ptr::null_mut(); - }; - let Some(layout) = rust_alloc_layout(size) else { - return core::ptr::null_mut(); - }; - let base = unsafe { alloc_zeroed(layout) }; - if base.is_null() { - return core::ptr::null_mut(); - } - unsafe { - *(base as *mut usize) = layout.size(); - base.add(LZMA_ALLOC_HEADER_SIZE) as *mut c_void - } -} - -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -unsafe fn free(ptr: *mut c_void) { - if ptr.is_null() { - return; - } - let base = unsafe { (ptr as *mut u8).sub(LZMA_ALLOC_HEADER_SIZE) }; - let total_size = unsafe { *(base as *const usize) }; - let layout = unsafe { Layout::from_size_align_unchecked(total_size, LZMA_ALLOC_ALIGN) }; - unsafe { dealloc(base, layout) }; -} pub const LZMA_VERSION_MAJOR: u32 = 5; pub const LZMA_VERSION_MINOR: u32 = 8; pub const LZMA_VERSION_PATCH: u32 = 3; @@ -80,39 +16,17 @@ pub fn lzma_version_number() -> u32 { pub fn lzma_version_string() -> *const c_char { crate::c_str!("5.8.3") } -pub unsafe fn lzma_alloc(mut size: size_t, allocator: *const lzma_allocator) -> *mut c_void { - if size == 0 { - size = 1; - } - let allocator = allocator_or_rust(allocator); - if let Some(alloc) = (*allocator).alloc { - alloc((*allocator).opaque, 1, size) - } else { - malloc(size) - } -} -pub unsafe fn lzma_alloc_zero(mut size: size_t, allocator: *const lzma_allocator) -> *mut c_void { - if size == 0 { - size = 1; +#[inline] +pub unsafe fn lzma_stream_allocator(strm: *const lzma_stream) -> *const lzma_allocator { + #[cfg(feature = "custom_allocator")] + { + unsafe { (*strm).allocator } } - let allocator = allocator_or_rust(allocator); - let ptr = if let Some(alloc) = (*allocator).alloc { - alloc((*allocator).opaque, 1, size) - } else { - calloc(1, size) - }; - if !ptr.is_null() { - core::ptr::write_bytes(ptr as *mut u8, 0, size); + #[cfg(not(feature = "custom_allocator"))] + { + let _ = strm; + core::ptr::null() } - ptr -} -pub unsafe fn lzma_free(ptr: *mut c_void, allocator: *const lzma_allocator) { - let allocator = allocator_or_rust(allocator); - if let Some(free_func) = (*allocator).free { - free_func((*allocator).opaque, ptr); - } else { - free(ptr); - }; } #[inline] pub unsafe fn lzma_alloc_object(allocator: *const lzma_allocator) -> *mut T { @@ -219,7 +133,7 @@ pub unsafe fn lzma_strm_init(strm: *mut lzma_stream) -> lzma_ret { return LZMA_PROG_ERROR; } if (*strm).internal.is_null() { - (*strm).internal = lzma_alloc_object::((*strm).allocator); + (*strm).internal = lzma_alloc_object::(lzma_stream_allocator(strm)); if (*strm).internal.is_null() { return LZMA_MEM_ERROR; } @@ -315,7 +229,7 @@ pub unsafe fn lzma_code(strm: *mut lzma_stream, action: lzma_action) -> lzma_ret let code = (*(*strm).internal).next.code.unwrap_unchecked(); let mut ret: lzma_ret = code( (*(*strm).internal).next.coder, - (*strm).allocator, + lzma_stream_allocator(strm), (*strm).next_in, ::core::ptr::addr_of_mut!(in_pos), (*strm).avail_in, @@ -381,9 +295,9 @@ pub unsafe fn lzma_end(strm: *mut lzma_stream) { if !strm.is_null() && !(*strm).internal.is_null() { lzma_next_end( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + lzma_stream_allocator(strm), ); - lzma_free((*strm).internal as *mut c_void, (*strm).allocator); + lzma_free((*strm).internal as *mut c_void, lzma_stream_allocator(strm)); (*strm).internal = core::ptr::null_mut(); } } diff --git a/xz-core/src/common/file_info.rs b/xz-core/src/common/file_info.rs index 312566be..eb917fb0 100644 --- a/xz-core/src/common/file_info.rs +++ b/xz-core/src/common/file_info.rs @@ -588,7 +588,7 @@ pub unsafe fn lzma_file_info_decoder( } let ret__0: lzma_ret = lzma_file_info_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), ::core::ptr::addr_of_mut!((*strm).seek_pos), dest_index, memlimit, diff --git a/xz-core/src/common/filter_decoder.rs b/xz-core/src/common/filter_decoder.rs index e8cdcebd..bf164888 100644 --- a/xz-core/src/common/filter_decoder.rs +++ b/xz-core/src/common/filter_decoder.rs @@ -314,7 +314,7 @@ pub unsafe fn lzma_raw_decoder(strm: *mut lzma_stream, options: *const lzma_filt } let ret__0: lzma_ret = lzma_raw_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), options, ); if ret__0 != LZMA_OK { diff --git a/xz-core/src/common/filter_encoder.rs b/xz-core/src/common/filter_encoder.rs index f8796392..5d81b454 100644 --- a/xz-core/src/common/filter_encoder.rs +++ b/xz-core/src/common/filter_encoder.rs @@ -314,7 +314,7 @@ pub unsafe fn lzma_filters_update(strm: *mut lzma_stream, filters: *const lzma_f let update = (*(*strm).internal).next.update.unwrap_unchecked(); update( (*(*strm).internal).next.coder, - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), filters, ::core::ptr::addr_of_mut!(reversed_filters) as *mut lzma_filter, ) @@ -339,7 +339,7 @@ pub unsafe fn lzma_raw_encoder(strm: *mut lzma_stream, filters: *const lzma_filt } let ret: lzma_ret = lzma_raw_coder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), filters, coder_find as unsafe fn(lzma_vli) -> *const lzma_filter_coder, true, diff --git a/xz-core/src/common/index_decoder.rs b/xz-core/src/common/index_decoder.rs index 2a18162b..cdbf7c66 100644 --- a/xz-core/src/common/index_decoder.rs +++ b/xz-core/src/common/index_decoder.rs @@ -342,7 +342,7 @@ pub unsafe fn lzma_index_decoder( } let ret__0: lzma_ret = lzma_index_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), i, memlimit, ); diff --git a/xz-core/src/common/index_encoder.rs b/xz-core/src/common/index_encoder.rs index 386b3a88..fa93074b 100644 --- a/xz-core/src/common/index_encoder.rs +++ b/xz-core/src/common/index_encoder.rs @@ -209,7 +209,7 @@ pub unsafe fn lzma_index_encoder(strm: *mut lzma_stream, i: *const lzma_index) - } let ret: lzma_ret = lzma_index_encoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), i, ); if ret != LZMA_OK { diff --git a/xz-core/src/common/lzip_decoder.rs b/xz-core/src/common/lzip_decoder.rs index 358c8799..64bcc80f 100644 --- a/xz-core/src/common/lzip_decoder.rs +++ b/xz-core/src/common/lzip_decoder.rs @@ -368,7 +368,7 @@ pub unsafe fn lzma_lzip_decoder(strm: *mut lzma_stream, memlimit: u64, flags: u3 } let ret__0: lzma_ret = lzma_lzip_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), memlimit, flags, ); diff --git a/xz-core/src/common/microlzma_decoder.rs b/xz-core/src/common/microlzma_decoder.rs index d483e5a0..2534e458 100644 --- a/xz-core/src/common/microlzma_decoder.rs +++ b/xz-core/src/common/microlzma_decoder.rs @@ -254,7 +254,7 @@ pub unsafe fn lzma_microlzma_decoder( } let ret: lzma_ret = microlzma_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), comp_size, uncomp_size, uncomp_size_is_exact != 0, diff --git a/xz-core/src/common/microlzma_encoder.rs b/xz-core/src/common/microlzma_encoder.rs index be4f28b8..e0a00fec 100644 --- a/xz-core/src/common/microlzma_encoder.rs +++ b/xz-core/src/common/microlzma_encoder.rs @@ -174,7 +174,7 @@ pub unsafe fn lzma_microlzma_encoder( } let ret: lzma_ret = microlzma_encoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), options, ); if ret != LZMA_OK { diff --git a/xz-core/src/common/stream_decoder.rs b/xz-core/src/common/stream_decoder.rs index 91a823b9..778a5cc9 100644 --- a/xz-core/src/common/stream_decoder.rs +++ b/xz-core/src/common/stream_decoder.rs @@ -394,7 +394,7 @@ pub unsafe fn lzma_stream_decoder(strm: *mut lzma_stream, memlimit: u64, flags: } let ret__0: lzma_ret = lzma_stream_decoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), memlimit, flags, ); diff --git a/xz-core/src/common/stream_decoder_mt.rs b/xz-core/src/common/stream_decoder_mt.rs index f7881aa7..a79e255e 100644 --- a/xz-core/src/common/stream_decoder_mt.rs +++ b/xz-core/src/common/stream_decoder_mt.rs @@ -53,6 +53,7 @@ pub struct worker_thread { pub in_pos: size_t, pub out_pos: size_t, pub coder: *mut lzma_stream_coder, + #[cfg(feature = "custom_allocator")] pub allocator: *const lzma_allocator, pub outbuf: *mut lzma_outbuf, pub progress_in: size_t, @@ -67,6 +68,31 @@ pub struct worker_thread { pub cond: mythread_cond, pub thread_id: mythread, } +#[inline] +unsafe fn worker_allocator(thr: *const worker_thread) -> *const lzma_allocator { + #[cfg(feature = "custom_allocator")] + { + unsafe { (*thr).allocator } + } + #[cfg(not(feature = "custom_allocator"))] + { + let _ = thr; + core::ptr::null() + } +} +#[inline] +unsafe fn set_worker_allocator(thr: *mut worker_thread, allocator: *const lzma_allocator) { + #[cfg(feature = "custom_allocator")] + { + unsafe { + (*thr).allocator = allocator; + } + } + #[cfg(not(feature = "custom_allocator"))] + { + let _ = (thr, allocator); + } +} pub const THR_EXIT: worker_state = 2; pub type stream_decoder_mt_seq = c_uint; pub const SEQ_ERROR: stream_decoder_mt_seq = 11; @@ -127,10 +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, (*thr).allocator); + crate::alloc::internal_free((*thr).in_0 as *mut c_void, worker_allocator(thr)); lzma_next_end( ::core::ptr::addr_of_mut!((*thr).block_decoder), - (*thr).allocator, + worker_allocator(thr), ); mythread_mutex_destroy(::core::ptr::addr_of_mut!((*thr).mutex)); mythread_cond_destroy(::core::ptr::addr_of_mut!((*thr).cond)); @@ -159,7 +185,7 @@ unsafe extern "C" fn worker_decoder(thr_ptr: *mut c_void) -> *mut c_void { ret = match (*thr).block_decoder.code { Some(code) => code( (*thr).block_decoder.coder, - (*thr).allocator, + worker_allocator(thr), (*thr).in_0, ::core::ptr::addr_of_mut!((*thr).in_pos), in_filled, @@ -215,7 +241,7 @@ 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, (*thr).allocator); + crate::alloc::internal_free((*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; @@ -344,7 +370,7 @@ unsafe fn initialize_new_thread( (*thr).state = THR_IDLE; (*thr).in_0 = core::ptr::null_mut(); (*thr).in_size = 0; - (*thr).allocator = allocator; + set_worker_allocator(thr, allocator); (*thr).coder = coder as *mut lzma_stream_coder; (*thr).outbuf = core::ptr::null_mut(); (*thr).block_decoder = lzma_next_coder_s { @@ -1554,7 +1580,7 @@ pub unsafe fn lzma_stream_decoder_mt(strm: *mut lzma_stream, options: *const lzm } let ret__0: lzma_ret = stream_decoder_mt_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), options, ); if ret__0 != LZMA_OK { diff --git a/xz-core/src/common/stream_encoder.rs b/xz-core/src/common/stream_encoder.rs index 49485364..68b0fcfd 100644 --- a/xz-core/src/common/stream_encoder.rs +++ b/xz-core/src/common/stream_encoder.rs @@ -413,7 +413,7 @@ pub unsafe fn lzma_stream_encoder( } let ret__0: lzma_ret = stream_encoder_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), filters, check, ); diff --git a/xz-core/src/common/stream_encoder_mt.rs b/xz-core/src/common/stream_encoder_mt.rs index 6aaac693..fdb38bb4 100644 --- a/xz-core/src/common/stream_encoder_mt.rs +++ b/xz-core/src/common/stream_encoder_mt.rs @@ -11,6 +11,7 @@ pub struct worker_thread_s { pub in_size: size_t, pub outbuf: *mut lzma_outbuf, pub coder: *mut lzma_stream_coder, + #[cfg(feature = "custom_allocator")] pub allocator: *const lzma_allocator, pub progress_in: u64, pub progress_out: u64, @@ -22,6 +23,31 @@ pub struct worker_thread_s { pub cond: mythread_cond, pub thread_id: mythread, } +#[inline] +unsafe fn worker_allocator(thr: *const worker_thread) -> *const lzma_allocator { + #[cfg(feature = "custom_allocator")] + { + unsafe { (*thr).allocator } + } + #[cfg(not(feature = "custom_allocator"))] + { + let _ = thr; + core::ptr::null() + } +} +#[inline] +unsafe fn set_worker_allocator(thr: *mut worker_thread, allocator: *const lzma_allocator) { + #[cfg(feature = "custom_allocator")] + { + unsafe { + (*thr).allocator = allocator; + } + } + #[cfg(not(feature = "custom_allocator"))] + { + let _ = (thr, allocator); + } +} pub type lzma_stream_coder = lzma_stream_coder_s; #[derive(Copy, Clone)] #[repr(C)] @@ -123,7 +149,7 @@ unsafe fn worker_encode( } ret = lzma_block_encoder_init( ::core::ptr::addr_of_mut!((*thr).block_encoder), - (*thr).allocator, + worker_allocator(thr), ::core::ptr::addr_of_mut!((*thr).block_options), ); if ret != LZMA_OK { @@ -183,7 +209,7 @@ unsafe fn worker_encode( }; ret = code( (*thr).block_encoder.coder, - (*thr).allocator, + worker_allocator(thr), (*thr).in_0, ::core::ptr::addr_of_mut!(in_pos), in_limit, @@ -346,15 +372,15 @@ unsafe extern "C" fn worker_start(thr_ptr: *mut c_void) -> *mut c_void { } lzma_filters_free( ::core::ptr::addr_of_mut!((*thr).filters) as *mut lzma_filter, - (*thr).allocator, + worker_allocator(thr), ); mythread_mutex_destroy(::core::ptr::addr_of_mut!((*thr).mutex)); mythread_cond_destroy(::core::ptr::addr_of_mut!((*thr).cond)); lzma_next_end( ::core::ptr::addr_of_mut!((*thr).block_encoder), - (*thr).allocator, + worker_allocator(thr), ); - crate::alloc::internal_free((*thr).in_0 as *mut c_void, (*thr).allocator); + crate::alloc::internal_free((*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) { @@ -468,7 +494,7 @@ unsafe fn initialize_new_thread( if mythread_mutex_init(::core::ptr::addr_of_mut!((*thr).mutex)) == 0 { if mythread_cond_init(::core::ptr::addr_of_mut!((*thr).cond)) == 0 { (*thr).state = THR_IDLE; - (*thr).allocator = allocator; + set_worker_allocator(thr, allocator); (*thr).coder = coder; (*thr).progress_in = 0; (*thr).progress_out = 0; @@ -1309,7 +1335,7 @@ pub unsafe fn lzma_stream_encoder_mt(strm: *mut lzma_stream, options: *const lzm } let ret__0: lzma_ret = stream_encoder_mt_init( ::core::ptr::addr_of_mut!((*(*strm).internal).next), - (*strm).allocator, + crate::common::common::lzma_stream_allocator(strm), options, ); if ret__0 != LZMA_OK { diff --git a/xz-core/src/types.rs b/xz-core/src/types.rs index 49869144..5b23bf38 100644 --- a/xz-core/src/types.rs +++ b/xz-core/src/types.rs @@ -79,6 +79,7 @@ pub struct lzma_stream { pub next_out: *mut u8, pub avail_out: size_t, pub total_out: u64, + #[cfg(feature = "custom_allocator")] pub allocator: *const lzma_allocator, pub internal: *mut lzma_internal, pub reserved_ptr1: *mut c_void, diff --git a/xz-sys/Cargo.toml b/xz-sys/Cargo.toml index 3e7d1264..5888948c 100644 --- a/xz-sys/Cargo.toml +++ b/xz-sys/Cargo.toml @@ -3,7 +3,7 @@ name = "xz-sys" version = "0.1.0" edition = "2024" license = "MIT OR Apache-2.0" -description = "liblzma-sys compatible API layer backed by pure Rust xz" +description = "liblzma-sys compatible API layer backed by pure Rust xz-core" [lib] crate-type = ["rlib", "staticlib"] @@ -22,5 +22,5 @@ parallel = [] wasm = ["static", "bindgen"] [dependencies] -xz-core = { path = "../xz-core" } +xz-core = { path = "../xz-core", features = ["custom_allocator"] } libc = "0.2" diff --git a/xz-sys/src/lib.rs b/xz-sys/src/lib.rs index ee64f781..bb332ef7 100644 --- a/xz-sys/src/lib.rs +++ b/xz-sys/src/lib.rs @@ -16,8 +16,6 @@ //! canonical types and thin wrapper functions that cast between structurally //! identical `#[repr(C)]` types. -mod c_allocator; - #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] use libc::size_t; #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] @@ -28,7 +26,6 @@ use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_void}; type wasm_size_t = usize; #[cfg(all(target_family = "wasm", target_os = "unknown"))] use self::wasm_size_t as size_t; -use crate::c_allocator::{normalize_c_allocator, normalize_c_stream_allocator}; /************************ * Canonical type aliases @@ -66,6 +63,16 @@ pub use xz_core::types::lzma_options_lzma; pub use xz_core::types::lzma_stream; pub use xz_core::types::lzma_stream_flags; +fn normalize_c_allocator(allocator: *const lzma_allocator) -> *const lzma_allocator { + xz_core::alloc::allocator_or_c(allocator.cast()).cast() +} + +unsafe fn normalize_c_stream_allocator(strm: *mut lzma_stream) { + if !strm.is_null() && (*strm).allocator.is_null() { + (*strm).allocator = xz_core::alloc::c_allocator_ptr().cast(); + } +} + #[repr(C)] pub struct lzma_options_bcj { pub start_offset: u32,