m4b / bingrep

like ~~grep~~ UBER, but for binaries

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

pager issue

hongxuchen opened this issue · comments

When using pager like less or more, bingrep works. However sometimes when it quits, it will panic. Here is a result when using bingrep with rustc with pager more.

Observations:

  1. This seems to happen for some binaries, e.g., there is no such a panic for /bin/ls on my machine.
  2. Other pager, e.g., view (from nvim) works fine when used like bingrep /path/to/target | view - however will hang forever when using wrongly, e.g., bingrep /path/to/target | view.
~ > RUST_BACKTRACE=1 bingrep ~/.cargo/bin/rustc  | more
thread 'main' panicked at 'Cannot print table to standard output : Broken pipe (os error 32)', /home/hongxu/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.6.7/src/lib.rs:188:12
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at /checkout/src/libstd/sys_common/backtrace.rs:68
             at /checkout/src/libstd/sys_common/backtrace.rs:57
   2: std::panicking::default_hook::{{closure}}
             at /checkout/src/libstd/panicking.rs:381
   3: std::panicking::default_hook
             at /checkout/src/libstd/panicking.rs:397
   4: std::panicking::rust_panic_with_hook
             at /checkout/src/libstd/panicking.rs:577
   5: std::panicking::begin_panic
             at /checkout/src/libstd/panicking.rs:538
   6: std::panicking::begin_panic_fmt
             at /checkout/src/libstd/panicking.rs:522
   7: prettytable::TableSlice::print_tty
   8: bingrep::format_elf::Elf::print::{{closure}}
   9: bingrep::format_elf::Elf::print
  10: bingrep::run
  11: bingrep::main
  12: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:101
  13: std::rt::lang_start
             at /checkout/src/libstd/panicking.rs:459
             at /checkout/src/libstd/rt.rs:58
  14: __libc_start_main
  15: _start
~ > file ~/.cargo/bin/rustc
/home/hongxu/.cargo/bin/rustc: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.9, not stripped
~ > /home/hongxu/.cargo/bin/rustc --version                                                                                                                                                               
rustc 1.24.0-nightly (2d4df9584 2017-12-10)
commented

Yea I don’t know; this seems to be the case with every rust binary binary piping to stdout I’ve used. Eg I’ve seen cargo do this.

I never bothered to look too deeply into it.

I’m welcome to anyone knowing the answer here though, and perhaps a quick fix to solve this for bingrep :)

Really weird, some other binaries are also affected. For example, bash/zsh, clang (but not gcc).

commented

If you find the cause you’ll be my hero :D

commented

So this is caused by writing to a closed pipe, which is common with piping to head and less.

We can fix this by taking stdio lock and try printing into it.

Will be complicated due to the various writers involved, eg pretty table and term color, but I think it should be fixable.

If anyone wants to give this a shot, let me know !

I see two solutions for this. The first would be to fix prettytable-rs crate which panics on I/O errors, even though I/O errors are fairly common. The second is to wrap all calls to TableSlice::print_tty() inside catch_unwind() and hope that the only cause of panic is an I/O error...

Given this issue, I don't think we can fix the library for the moment. The next best thing I see is to catch those panics. Another solution would be to fork the library and continue maintaining it.

You can use TableSlice::print(&mut std::io::stdout()) or TableSlice::print_term(&mut term::stdout()) (depending on if stdout is a tty) and ignore the result I think. Basically copy the print_tty() function and remove the panic.

Programs usually don't check the return value of printf() and related output functions, so that EPIPE errors don't actually print anything, and that makes the output of head, more and the likes reasonable. A more honest output, that still doesn't panic, would be like this:

$ target/debug/bingrep /bin/ls|head
ELF DYN X86_64-little-endian @ 0x6180:

e_phoff: 0x40 e_shoff: 0x23768 e_flags: 0x0 e_ehsize: 64 e_phentsize: 56 e_phnum: 11 e_shentsize: 64 e_shnum: 30 e_shstrndx: 29

ProgramHeaders(11):
  Idx   Type              Flags   Offset     Vaddr      Paddr      Filesz     Memsz      Align   
  0     PT_PHDR           R       0x40       0x40       0x40       0x268      0x268      0x8     
  1     PT_INTERP         R       0x2a8      0x2a8      0x2a8      0x1c       0x1c       0x1     
  2     PT_LOAD           R       0x0        0x0        0x0        0x3538     0x3538     0x1000  
  3     PT_LOAD           R+X     0x4000     0x4000     0x4000     0x143c9    0x143c9    0x1000  
Broken pipe (os error 32)

I think, for ergonomic reasons, we should not display the Broken pipe (os error 32), but instead just exit silently.

SIGPIPE by default causes the program to exit even if the program doesn't check the return value of printf(). Libstd overrides the signal handler to do nothing and instead allow reading and writing to result in an error. println!() and prettytable both decided to panic when an error happens as otherwise the program would silently try to keep running.

So should I filter out the Broken pipe (os error 32) error? Or keep reproting it?

Filtering it would be fine I think.