Image: panic while reading valid Jpeg image

Created on 26 Feb 2020  路  16Comments  路  Source: image-rs/image

This happens in image::open

Expected

No panic

Actual behaviour

Panic

Reproduction steps

image::open() the image from this url:
https://cdn.aboutyou.de/file/90084b3edf1b97f95ca05c245721d554?width=2000&height=2000

produces this stack trace:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `2800000`,
 right: `2816000`: destination and source slices have different lengths', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/macros/mod.rs:23:13
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:84
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1025
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:193
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:210
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:471
  11: rust_begin_unwind
             at src/libstd/panicking.rs:375
  12: core::panicking::panic_fmt
             at src/libcore/panicking.rs:84
  13: core::slice::<impl [T]>::copy_from_slice
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/macros/mod.rs:21
  14: <image::jpeg::decoder::JpegDecoder<R> as image::image::ImageDecoder>::read_image
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/jpeg/decoder.rs:82
  15: image::image::decoder_to_vec
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/image.rs:293
  16: image::dynimage::decoder_to_image
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/dynimage.rs:878
  17: image::dynimage::DynamicImage::from_decoder
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/dynimage.rs:185
  18: image::io::free_functions::load
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/io/free_functions.rs:68
  19: image::io::free_functions::open_impl
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/io/free_functions.rs:51
  20: image::dynimage::open
             at /Users/kosta/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.0/./src/dynimage.rs:953
  21: image_panic::main
             at src/main.rs:2
  22: std::rt::lang_start::{{closure}}
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  23: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  24: std::panicking::try::do_call
             at src/libstd/panicking.rs:292
  25: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:78
  26: std::panicking::try
             at src/libstd/panicking.rs:270
  27: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  28: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  29: std::rt::lang_start
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  30: image_panic::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
bug

Most helpful comment

Good news: I just used Cargo's patch feature to confirm that the latest master of jpeg-decoder doesn't have the issue anymore! (https://github.com/image-rs/jpeg-decoder.git#0920c4c506d2efbc58c5a1a03879e0eb66eb1200).

All 16 comments

The buffer left has correct size (1,400px 脳 2,000px) so the fault is likely in jpeg-decoder.

The issue #1165 identified that in this function the clone_from_slice fails. The prior assert_eq appears to validate that sizes match but apparently the size of the final decode block does not equal the one calculated from total_bytes.

Note that jpeg is split into blocks of 8x8 pixels. My current best guess would be that some function incorrectly calculates the number of such blocks for some images. Note that the difference between the expected sizes in both this issue and in #1165 is divisble by 64.

@kosta Is this your image, i.e. do you have some clarify on copyright? We'd like to add it as a test case to jpeg-decoder if possible.

I'm sorry this is an image from a german online shop that I tried to process. I don't have any insights on their copyright.

Thanks for the clarification then, that's what I expected.

I tried to reproduce this issue but I can't. The image for the link above (sha1: 293b2f338204fc398ecbcc9ee06aa1d6f806d58a) is decoded correctly by both image-rs and the underlying jpeg-decoder. Is there something I am missing ?

Given the size of the image, it would have been affected by https://github.com/image-rs/jpeg-decoder/issues/148 if it were encoded as a grayscale JPEG with a horizontal sampling factor of 2. The bug would then have returned a buffer of size ceil(1400/16)*16 脳 2,000 = 2816000, which is exactly what is reported here.

And since the image contains no color, imagemagick defaults to encoding it as grayscale when it goes through it...

So, there is no proof, but I would bet that the exact image file that caused this bug is not the one referenced...

@lovasoa The image has indeed changed, the original broken image has a sha1 of 4873b0d65e3cc096b95e667bd637fb1835d37376 while now the linked image has a sha1 of 293b2f338204fc398ecbcc9ee06aa1d6f806d58a.

Because of copyright issues, I can't provide a copy of the original affected image. Is there something I can do myself to confirm your suspicions. Maybe provide me with a list of information about the image I can collect?

Also there is a second image that seems to trigger a similar bug, but definitely has color. Not sure if it's the same issue. But same copyright problem there sadly.

Thanks for replying. What may be helpful is to paste the result of identify -verbose yourimage.jpg together with the exact error message and stack trace returned by image-rs.

Apparently I was incorrect about assuming that the second image had colors ...

$ identify broken.jpg
broken.jpg JPEG 1400x2000 1400x2000+0+0 8-bit Gray 256c 525431B 0.000u 0:00.000
$ identify broken2.jpg 
broken2.jpg JPEG 1400x2000 1400x2000+0+0 8-bit Gray 256c 51833B 0.000u 0:00.000

Backtrace 1 (broken.jpg):

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `2800000`,
 right: `2816000`: destination and source slices have different lengths', /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libcore/macros/mod.rs:18:13
stack backtrace:
   0:     0x55df5c409f04 - backtrace::backtrace::libunwind::trace::h5ae3454ebe40b621
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1:     0x55df5c409f04 - backtrace::backtrace::trace_unsynchronized::hbf6f267a483fb2c0
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2:     0x55df5c409f04 - std::sys_common::backtrace::_print_fmt::h37755015d94b9085
                               at src/libstd/sys_common/backtrace.rs:78
   3:     0x55df5c409f04 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h0561c8cd3569b40d
                               at src/libstd/sys_common/backtrace.rs:59
   4:     0x55df5c425c7c - core::fmt::write::h86a597a35d48a212
                               at src/libcore/fmt/mod.rs:1063
   5:     0x55df5c407803 - std::io::Write::write_fmt::h73d9dc0f29eefe48
                               at src/libstd/io/mod.rs:1426
   6:     0x55df5c40c6f5 - std::sys_common::backtrace::_print::h6c60c5ee09af0233
                               at src/libstd/sys_common/backtrace.rs:62
   7:     0x55df5c40c6f5 - std::sys_common::backtrace::print::hf9d1db01634f9b2a
                               at src/libstd/sys_common/backtrace.rs:49
   8:     0x55df5c40c6f5 - std::panicking::default_hook::{{closure}}::h1db9298dd213ae95
                               at src/libstd/panicking.rs:204
   9:     0x55df5c40c442 - std::panicking::default_hook::h3272faf6cc91fd2e
                               at src/libstd/panicking.rs:224
  10:     0x55df5c40cd52 - std::panicking::rust_panic_with_hook::hb976084785e50594
                               at src/libstd/panicking.rs:470
  11:     0x55df5c40c93b - rust_begin_unwind
                               at src/libstd/panicking.rs:378
  12:     0x55df5c424ff1 - core::panicking::panic_fmt::h45f7d6868edb5678
                               at src/libcore/panicking.rs:85
  13:     0x55df5c2e1c80 - core::slice::<impl [T]>::copy_from_slice::h166b79d1c4b27124
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libcore/macros/mod.rs:16
  14:     0x55df5c23b7ff - <image::jpeg::decoder::JpegDecoder<R> as image::image::ImageDecoder>::read_image::h79d5a5931f91c3fb
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/jpeg/decoder.rs:84
  15:     0x55df5c228a3e - image::image::decoder_to_vec::hab4af7f73b5a1974
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/image.rs:309
  16:     0x55df5c1d6c43 - image::dynimage::decoder_to_image::hdc56dfa8c4592235
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:898
  17:     0x55df5c1c6e6c - image::dynimage::DynamicImage::from_decoder::h0793d3f0f2e6489f
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:190
  18:     0x55df5c1880ab - image::io::free_functions::load::h16d4e161c556e230
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/io/free_functions.rs:70
  19:     0x55df5c187906 - image::io::free_functions::open_impl::he343f2731c808c48
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/io/free_functions.rs:53
  20:     0x55df5c17f5cc - image::dynimage::open::h6447dcc9ffd80969
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:978
  21:     0x55df5c17f310 - reproducer::main::hec48884307718fca
                               at src/main.rs:2
  22:     0x55df5c17f55b - std::rt::lang_start::{{closure}}::hbad75d72ef3b83e5
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libstd/rt.rs:67
  23:     0x55df5c40c813 - std::rt::lang_start_internal::{{closure}}::hc0a1280e68ffc5da
                               at src/libstd/rt.rs:52
  24:     0x55df5c40c813 - std::panicking::try::do_call::h1d43a4d29f303ef5
                               at src/libstd/panicking.rs:303
  25:     0x55df5c40f617 - __rust_maybe_catch_panic
                               at src/libpanic_unwind/lib.rs:86
  26:     0x55df5c40d33c - std::panicking::try::h5ef738612ab0072d
                               at src/libstd/panicking.rs:281
  27:     0x55df5c40d33c - std::panic::catch_unwind::h1df9a04c7f1c6fc3
                               at src/libstd/panic.rs:394
  28:     0x55df5c40d33c - std::rt::lang_start_internal::h97d4af4643f4b0e4
                               at src/libstd/rt.rs:51
  29:     0x55df5c17f537 - std::rt::lang_start::h4d6f8107305c5feb
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libstd/rt.rs:67
  30:     0x55df5c17f38a - main
  31:     0x7fd3054bc023 - __libc_start_main
  32:     0x55df5c17f15e - _start
  33:                0x0 - <unknown>

broken2.jpg:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `2800000`,
 right: `2816000`: destination and source slices have different lengths', /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libcore/macros/mod.rs:18:13
stack backtrace:
   0:     0x55b47b213f04 - backtrace::backtrace::libunwind::trace::h5ae3454ebe40b621
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1:     0x55b47b213f04 - backtrace::backtrace::trace_unsynchronized::hbf6f267a483fb2c0
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2:     0x55b47b213f04 - std::sys_common::backtrace::_print_fmt::h37755015d94b9085
                               at src/libstd/sys_common/backtrace.rs:78
   3:     0x55b47b213f04 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h0561c8cd3569b40d
                               at src/libstd/sys_common/backtrace.rs:59
   4:     0x55b47b22fc7c - core::fmt::write::h86a597a35d48a212
                               at src/libcore/fmt/mod.rs:1063
   5:     0x55b47b211803 - std::io::Write::write_fmt::h73d9dc0f29eefe48
                               at src/libstd/io/mod.rs:1426
   6:     0x55b47b2166f5 - std::sys_common::backtrace::_print::h6c60c5ee09af0233
                               at src/libstd/sys_common/backtrace.rs:62
   7:     0x55b47b2166f5 - std::sys_common::backtrace::print::hf9d1db01634f9b2a
                               at src/libstd/sys_common/backtrace.rs:49
   8:     0x55b47b2166f5 - std::panicking::default_hook::{{closure}}::h1db9298dd213ae95
                               at src/libstd/panicking.rs:204
   9:     0x55b47b216442 - std::panicking::default_hook::h3272faf6cc91fd2e
                               at src/libstd/panicking.rs:224
  10:     0x55b47b216d52 - std::panicking::rust_panic_with_hook::hb976084785e50594
                               at src/libstd/panicking.rs:470
  11:     0x55b47b21693b - rust_begin_unwind
                               at src/libstd/panicking.rs:378
  12:     0x55b47b22eff1 - core::panicking::panic_fmt::h45f7d6868edb5678
                               at src/libcore/panicking.rs:85
  13:     0x55b47b0ebc80 - core::slice::<impl [T]>::copy_from_slice::h166b79d1c4b27124
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libcore/macros/mod.rs:16
  14:     0x55b47b0457ff - <image::jpeg::decoder::JpegDecoder<R> as image::image::ImageDecoder>::read_image::h79d5a5931f91c3fb
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/jpeg/decoder.rs:84
  15:     0x55b47b032a3e - image::image::decoder_to_vec::hab4af7f73b5a1974
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/image.rs:309
  16:     0x55b47afe0c43 - image::dynimage::decoder_to_image::hdc56dfa8c4592235
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:898
  17:     0x55b47afd0e6c - image::dynimage::DynamicImage::from_decoder::h0793d3f0f2e6489f
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:190
  18:     0x55b47af920ab - image::io::free_functions::load::h16d4e161c556e230
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/io/free_functions.rs:70
  19:     0x55b47af91906 - image::io::free_functions::open_impl::he343f2731c808c48
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/io/free_functions.rs:53
  20:     0x55b47af895cc - image::dynimage::open::h6447dcc9ffd80969
                               at /home/max/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.23.4/./src/dynimage.rs:978
  21:     0x55b47af89310 - reproducer::main::hec48884307718fca
                               at src/main.rs:2
  22:     0x55b47af8955b - std::rt::lang_start::{{closure}}::hbad75d72ef3b83e5
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libstd/rt.rs:67
  23:     0x55b47b216813 - std::rt::lang_start_internal::{{closure}}::hc0a1280e68ffc5da
                               at src/libstd/rt.rs:52
  24:     0x55b47b216813 - std::panicking::try::do_call::h1d43a4d29f303ef5
                               at src/libstd/panicking.rs:303
  25:     0x55b47b219617 - __rust_maybe_catch_panic
                               at src/libpanic_unwind/lib.rs:86
  26:     0x55b47b21733c - std::panicking::try::h5ef738612ab0072d
                               at src/libstd/panicking.rs:281
  27:     0x55b47b21733c - std::panic::catch_unwind::h1df9a04c7f1c6fc3
                               at src/libstd/panic.rs:394
  28:     0x55b47b21733c - std::rt::lang_start_internal::h97d4af4643f4b0e4
                               at src/libstd/rt.rs:51
  29:     0x55b47af89537 - std::rt::lang_start::h4d6f8107305c5feb
                               at /rustc/4fb7144ed159f94491249e86d5bbd033b5d60550/src/libstd/rt.rs:67
  30:     0x55b47af8938a - main
  31:     0x7fda2a63f023 - __libc_start_main
  32:     0x55b47af8915e - _start
  33:                0x0 - <unknown>

Good news: I just used Cargo's patch feature to confirm that the latest master of jpeg-decoder doesn't have the issue anymore! (https://github.com/image-rs/jpeg-decoder.git#0920c4c506d2efbc58c5a1a03879e0eb66eb1200).

Marking as fixed then, with release 0.1.19. Run cargo update -p jpeg-decoder to receive the fix.

Thanks a lot!

Sorry for being such a bad bug reporter - but thank you for fixing this bug!

Was this page helpful?
0 / 5 - 0 ratings