Giter Club home page Giter Club logo

zune-jpeg's People

Contributors

5225225 avatar etemesi254 avatar shnatsel avatar sludgephd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

zune-jpeg's Issues

`align_alloc` is unsound

Referring to:

let layout = Layout::from_size_align_unchecked(capacity * size_of::<T>(), ALIGNMENT);
// Use alloc zeroed to prevent page faults .So let me talk about this
// The kernel mmap modifies page tables when calling malloc, but doesn't allocate actual memory
// This is an optimization technique because allocating memory that won't be used is wasteful.
// During writing to a new page, a page fault is triggered and the code moves to kernel space.
// The kernel maps the page to memory and returns to user space.
// This is ideally wasteful, if the memory will be written after being allocated, so what alloc_zeroed
// does is trigger all page faults before we actually write to ensure we have mapped memory.
//
// Although it appears in flame-graphs as taking a lot of time to call, trust me it's better than
// page faults every 4 KB's
let ptr = alloc_zeroed(layout);
Vec::<T>::from_raw_parts(ptr.cast(), capacity, capacity)

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.

Panic while panicking after an out-of-bounds index on real-world images

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

138_1.jpg

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)

Valid JPEG fails to decode ("Wrong QT bit set")

The following image decodes fine in Firefox, VS Code, and jpeg-decoder, but fails to decode with zune-jpeg:

error

(it doesn't seem to be able to decode any image output by my webcam, they all produce this error)

Panic with 'called `Option::unwrap()` on a `None` value' in worker.rs:227:64 on real-world images

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)

Out-of-bounds indexing panic in `color_convert::scalar::ycbcr_to_grayscale` on real-world images

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

Panic with 'called `Option::unwrap()` on a `None` value' in mcu.rs:383:48 on a real-world image

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)

Heap buffer overflow on some images in v0.1.4

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)

zune-jpeg 1.5x slower than libjpeg-turbo on the attached image

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'

Panics discovered by fuzzer

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.

Parallelize Huffman decoding on files with restart markers

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

Project status & collaboration with jpeg-decoder?

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?

The attached real-world image fails to decode

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!

Panic on some real-world images at mcu.rs:354:48

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.

1130214.jpg

The code to reproduce it is the same as in #10

Tested on commit 1f92bac

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.