etemesi254 / zune-jpeg Goto Github PK
View Code? Open in Web Editor NEWA jpeg decoder with wings
A jpeg decoder with wings
Referring to:
Lines 183 to 199 in 27c2c38
Quoting Vec::from_raw_parts, emphasis by me:
T needs to have the same size and alignment as what ptr was allocated with. (T having a less strict alignment is not sufficient, the alignment really needs to be equal to satisfy the dealloc requirement that memory must be allocated and deallocated with the same layout.)
This is exactly what the code is doing here.
The attached image triggers the following panic in zune-jpeg:
thread '<unnamed>' panicked at 'range end index 13761 out of range for slice of length 13344', library/core/src/slice/index.rs:73:5
The panic seems to occur in all worker threads, and then trigger another panic when propagated to the caller, causing the process to abort.
The code to reproduce it is the same as in #10
Tested on commit e99e93c (latest as of this writing)
The attached image causes zune-jpeg to panic when decoding it: bg_header.jpg
Backtrace:
called `Option::unwrap()` on a `None` value', /home/shnatsel/Code/zune-jpeg/src/worker.rs:227:64
0: rust_begin_unwind
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:142:14
2: core::panicking::panic
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:48:5
3: core::option::Option<T>::unwrap
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/option.rs:755:21
4: zune_jpeg::worker::color_convert_ycbcr
at /home/shnatsel/Code/zune-jpeg/src/worker.rs:227:32
5: zune_jpeg::worker::post_process_inner
at /home/shnatsel/Code/zune-jpeg/src/worker.rs:163:13
6: zune_jpeg::worker::post_process
at /home/shnatsel/Code/zune-jpeg/src/worker.rs:82:5
7: zune_jpeg::mcu::<impl zune_jpeg::decoder::Decoder>::decode_mcu_ycbcr_baseline::{{closure}}::{{closure}}
at /home/shnatsel/Code/zune-jpeg/src/mcu.rs:386:21
8: <F as scoped_threadpool::FnBox>::call_box
at /home/shnatsel/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped_threadpool-0.1.9/src/lib.rs:71:9
9: scoped_threadpool::Pool::new::{{closure}}
at /home/shnatsel/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped_threadpool-0.1.9/src/lib.rs:127:29
Tested on commit d2aaf01 (latest as of this writing)
Decoding the attached image results in a panic:
thread '<unnamed>' panicked at 'range end index 9216 out of range for slice of length 8192'
Since this happens in a worker thread there's also a panic-while-panicking.
The last zune-jpeg function in the backtrace is zune_jpeg::color_convert::scalar::ycbcr_to_grayscale
.
Tested on commit e34e5bd (latest as of this writing)
Here's the image to trigger it: ScarRuffModel.jpg
This image (4096x2160 pixels) fails to decode with
Error: Error decoding huffman values: Bad Huffman Code 0xFFAC, corrupt JPEG
Some down sampled images generate unprocessed last stripes which the decoder doesn't handle.
This issue is created to remind you of that.
The attached image causes zune-jpeg to panic when decoding it: Crocosmia_by_sirpecangum
Backtrace:
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /home/shnatsel/Code/zune-jpeg/src/mcu.rs:383:48
stack backtrace:
0: rust_begin_unwind
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:142:14
2: core::panicking::panic
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:48:5
3: core::option::Option<T>::unwrap
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/option.rs:755:21
4: zune_jpeg::mcu::<impl zune_jpeg::decoder::Decoder>::decode_mcu_ycbcr_baseline::{{closure}}
at /home/shnatsel/Code/zune-jpeg/src/mcu.rs:383:34
5: scoped_threadpool::Pool::scoped
at /home/shnatsel/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped_threadpool-0.1.9/src/lib.rs:181:9
6: zune_jpeg::mcu::<impl zune_jpeg::decoder::Decoder>::decode_mcu_ycbcr_baseline
at /home/shnatsel/Code/zune-jpeg/src/mcu.rs:245:9
7: zune_jpeg::decoder::Decoder::decode_internal
at /home/shnatsel/Code/zune-jpeg/src/decoder.rs:428:13
8: zune_jpeg::decoder::Decoder::decode_file
at /home/shnatsel/Code/zune-jpeg/src/decoder.rs:220:9
9: zune_jpeg_bench::main
at ./src/main.rs:9:5
10: core::ops::function::FnOnce::call_once
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/ops/function.rs:248:5
Tested on commit d2aaf01 (latest as of this writing)
I've run zune-jpeg
on an imageboard dump I obtained specifically for testing image decoders. Some of the images trigger a segmentation fault with a heap buffer overflow with the x86 feature enabled, or a panic with that feature disabled. A sample image triggering the issue is attached: 1637407.jpg
Code to reproduce:
use zune_jpeg::Decoder;
use std::fs::File;
use std::io::BufReader;
fn main() -> std::io::Result<()> {
let path = std::env::args().skip(1).next().unwrap();
let mut decoder = Decoder::new();
decoder.decode_file(path);
Ok(())
}
You can build it in release mode as normal and observe a segmentation fault, or you can build it with address sanitizer to get more details: RUSTFLAGS=-Zsanitizer=address cargo +nightly build --release --target=x86_64-unknown-linux-gnu
(replace "x86_64-unknown-linux-gnu" with your native platform)
This image (too big for Github) is decoded 1.5x slower by zune-jpeg than by libjpeg-turbo.
Profiling shows that 65% of the time is spent in zune_jpeg::bitstream::BitStream::decode_mcu_block
function.
Interactive profile showing where the time is spent: https://share.firefox.dev/3J5gEcw
Tested on Ubuntu 20.04, on an AMD Zen CPU in 64-bit mode, using libjpeg-turbo version 2.0.3-0ubuntu1.20.04.1
, zune-jpeg from git on commit 3b1ab46 (latest as of this writing) with the x86 feature enabled
Code used:
use zune_jpeg::Decoder;
use std::fs::File;
use std::io::BufReader;
fn main() -> std::io::Result<()> {
let path = std::env::args().skip(1).next().unwrap();
let mut decoder = Decoder::new();
decoder.decode_file(path);
Ok(())
}
Performance measured with hyperfine
, like this:
> hyperfine -w 5 'target/release/zune-jpeg-bench ~//2786525.jpg' 'djpeg ~/2786525.jpg > /dev/null'
Benchmark 1: target/release/zune-jpeg-bench ~//2786525.jpg
Time (mean ± σ): 503.0 ms ± 15.7 ms [User: 642.6 ms, System: 56.1 ms]
Range (min … max): 485.0 ms … 535.8 ms 10 runs
Benchmark 2: djpeg ~/2786525.jpg > /dev/null
Time (mean ± σ): 319.8 ms ± 0.2 ms [User: 310.9 ms, System: 8.6 ms]
Range (min … max): 319.4 ms … 320.2 ms 10 runs
Summary
'djpeg ~/2786525.jpg > /dev/null' ran
1.57 ± 0.05 times faster than 'target/release/zune-jpeg-bench ~//2786525.jpg'
I have decoded the AFL-generated set of exotic JPEGs when fuzzing libjpeg-turbo, as well as the files generated by AFL when targeting the jpeg-decoder
crate. Decoding these files causes multiple panics in zune-jpeg
.
The set of files triggering the panics is attached: jpeg_fuzzing_seeds.tar.gz
Aside of being interesting test cases, these files can also be used to kickstart fuzzing - simply put them into fuzz/corpus/decode_buffer
and run the fuzzer as usual. This should provide much better coverage than starting from scratch.
Restart markers provide explicit restart points for Huffman code. Not all JPEG files have them, but on those that do, Huffman decoding can be performed in parallel.
I expect this to result in significant gains because at least on x86 decoding is bottlenecked on Huffman decoding - in fact, all the parts that are parallelized are faster than Huffman decoding and only utilize 70% of a single CPU core on my machine, while Huffman decoding uses 100% of its core. Profile to back that up: https://share.firefox.dev/3N67OMG
Hello Caleb,
I am really excited to see a speedy JPEG decoder in Rust! I've been working on speeding up jpeg-decoder
, and seeing outdoing libjpeg-turbo
already accomplished by someone else is amazing!
First, I see that your project is license-compatible with jpeg-decoder
- I think there is a lot both projects could get from code sharing. For example, jpeg-decoder
has IDCT routines in ARM NEON which might be worth integrating into zune-jpeg
, while jpeg-decoder
could pick up your Huffman decoding implementation which is its primary bottleneck. Would you be open to integrating the useful parts of jpeg-decoder
into zune-jpeg
?
Second, do you feel the project is at a stage where compatibility and robustness testing makes sense? I could help with fuzzing as well as testing on real-world data (I have plenty of experience with both), but that only makes sense as long as the project is not in flux and you're actually ready to deal with the reported bugs.
Finally, would you be open to integration with the image
crate so that its users could use zune-jpeg
in place of the current default of jpeg-decoder
?
zune-jpeg seems to fail to decode photos taken by Google Pixel phones. They display correctly in web browsers and my desktop image viewer, as well as jpeg-decoder
crate.
Sample file demonstrating the issue: PXL_20220202_150158375
This 14k by 19k image fails to decode correctly in zune-jpeg. I have not inspected the output, but decoding completes in 15ms while djpeg takes well over a second, which sounds too good to be true.
This is an AI upscale of the image used in #15 - same content, different resolution. Don't mix them up!
The attached image triggers the following panic in zune-jpeg:
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', zune-jpeg/src/mcu.rs:354:48
It happens on 88 images out of ~5500 images I have tested. It seems to be the only panic to occur on this dataset.
The code to reproduce it is the same as in #10
Tested on commit 1f92bac
Hello. As I understand the work moved over to https://github.com/etemesi254/zune-image, so it’s probably a good idea to archive this repo and point to the new one?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.