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:
- This seems to happen for some binaries, e.g., there is no such a panic for
/bin/ls
on my machine. - Other pager, e.g.,
view
(from nvim) works fine when used likebingrep /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)
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
).
If you find the cause you’ll be my hero :D
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.