phsym/prettytable-rs

Crash due to subtract with overflow

alexanderkjall opened this issue · 4 comments

Hi, I did some fuzzing of a crates that uses this library, and found the following crash:

thread 'main' panicked at 'attempt to subtract with overflow', src/utils.rs:106:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:475
   1: core::panicking::panic_fmt
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:85
   2: core::panicking::panic
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:50
   3: prettytable::utils::display_width
             at ./src/utils.rs:106
   4: prettytable::cell::Cell::new_align
             at ./src/cell.rs:30
   5: prettytable::cell::Cell::new
             at ./src/cell.rs:47
   6: crash::main::{{closure}}::{{closure}}
             at ./examples/crash.rs:17
   7: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:280
   8: core::option::Option<T>::map
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:437
   9: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::next
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/mod.rs:844
  10: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec.rs:2116
  11: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec.rs:2018
  12: core::iter::traits::iterator::Iterator::collect
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:1653
  13: crash::main::{{closure}}
             at ./examples/crash.rs:17
  14: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:280
  15: core::option::Option<T>::map
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:437
  16: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::next
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/mod.rs:844
  17: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec.rs:2116
  18: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec.rs:2018
  19: core::iter::traits::iterator::Iterator::collect
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:1653
  20: crash::main
             at ./examples/crash.rs:15
  21: core::ops::function::FnOnce::call_once
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227

It can be reproduced with the following program:

use prettytable::{csv::ReaderBuilder, Table, Row, Cell, format};

use std::io::Cursor;

fn main() {
    let data: Vec<u8> = vec![125, 27, 27, 27, 91, 27, 91, 125, 91, 27, 10, 9];
    let reader = Box::new(Cursor::new(data));

    let csv_reader = &mut ReaderBuilder::new()
        .delimiter('\t' as u8)
        .has_headers(false)
        .from_reader(reader);

    let mut table = Table::init(
        csv_reader
            .records()
            .map(|row| Row::new(row.unwrap().into_iter().map(|cell| Cell::new(&cell)).collect()))
            .collect(),
    );
    table.set_format(format::TableFormat::new());
    table.printstd();
}

Ha, just ran across this independently in #137. That's a fix for it, in any case.

Will close this when I've cut 1.0.0 hopefully today - I've merged the panic fix - fuzz tyvm!

I merged the fix - tyvm @5225225 - the repro instead of attempt to subtract with overflow:

$ cargo run

thread 'main' panicked at 'attempt to subtract with overflow', /home/foobar/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.9.0/src/utils.rs:106:5

We now get UnequalLengths unhandled error panic in repro which comes from csv crate

$ cargo run

     Running `target/debug/test-fuzz-pretty`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error(UnequalLengths { pos: Some(Position { byte: 11, line: 2, record: 1 }), expected_len: 1, len: 2 })', src/main.rs:17:37

Adding ReaderBuilder.flexible(true) gets past that unhandled error in repro panic.

The output becames }ESCESCESC[ESC[}[ESC but no panic so works as expected now with empty table format.

Release 0.10.0 is out with this fixed 🥳