How I wound up finding a bug in GNU Tar
utcc.utoronto.ca
utcc.utoronto.ca
catch syscall read
commmands
backtrace
continue
end
Put that into a file `trace-read.gdb` and attach to a running process like so: gdb -x trace-read.gdb -p $(pgrep -n tar)
This assumes you are running an executable with built-in debugging symbols (gcc -g). It should be possible to side-load debugging symbols provided in an external package, though I don't have a command at hand. (Anyone?)This works well enough on Linux, to quickly debug situations like the one above. However, it can make the attached process painfully slow, and occasionally bring it down all-together.
The right tool for this kind of in situations where slowing down or crashing the process is not acceptable, is DTrace:
dtrace -p $(pgrep -n tar) -n 'syscall::read:entry { ustack(); }'
- Tutorial: https://wiki.freebsd.org/DTrace/Tutorial- ustack: http://dtrace.org/guide/chp-user.html#chp-user-4
Ironically, DTrace is one of the main selling points for Solaris/OmniOS (or FreeBSD) over Linux. The situation has gotten better recently, with bpftrace becoming available:
- http://www.brendangregg.com/blog/2018-10-08/dtrace-for-linux...
- https://github.com/iovisor/bpftrace
Until you have a 4.x Kernel with the right configuration options running, I am afraid the above gdb scripts is your best option on Linux.
$ perf record -e syscalls:sys_enter_read -g -- application arg1 arg2 ...
[ application runs while perf writes out a log, recording every read() syscall, and keeping track of the backtrace each time]
$ perf report -g --stdio
[ perf reads the log, writing out the backtraces ]
This is the basic usage. Lots more is available, obviously. This has been available for a LONG time.It started out as an implementation of tar written by John Gilmore whose uname is 'gnu'. gnu has written a lot of free software as well, but the fact that his name and the GNU project's name are the same is a complete coincidence.
I'm not saying that I disbelieve you, I just haven't been able to find any references for your claim.
ChangeLog.1 and NEWS only go back to after it was migrated to the GNU project (http://git.savannah.gnu.org/gitweb/?p=tar.git;a=tree), his personal site, http://www.toad.com/gnu/ seems to be down but an archive (https://web.archive.org/web/20180623140434/http://www.toad.c...) just says 'In 1985 I wrote the "pdtar" program, which eventually became GNU Tar.'
He clearly uses the name "gnu", but did that usage predate the GNU project? I haven't found a reference for that.
——
Rust in general is pretty exciting for systems work. I just wish there were more shops using it professionally.
/feels cold shiver wondering if i've every used read()/
EOF is not zero.
It cannot be, because it must be outside the range of `char`.
On my (linux) system, EOF happens to be -1.
This is explained in in the first chapter of K&R.
On success, the number of bytes read is returned (zero indicates end
of file), and the file position is advanced by this number. [...]
On error, -1 is returned, and errno is set appropriately. In this
case, it is left unspecified whether the file position (if any)
changes.I wonder why they chose not to use out of range values for EOF there, given that `getchar` surely predates `read`?
With getchar(), the decision was made to return the char directly (to have used a pointer to a single char would be daft, from the point of view of economy) and to use an in-band code to indicate end of file. This "in-band signalling" is considered a bit of a kludge by some people. So I'd say read() is a better/cleaner design.
See https://en.wikipedia.org/wiki/Semipredicate_problem for some related thoughts.
(The V7 getc/getchar/etc manpage notes this as a BUG, although it doesn't specifically document what the V1-V6 EOF was. Presumably everyone who this was relevant for already knew. All of this is based on the historical Unix trees available through www.tuhs.org.)
Is that a bug? Yes. It's different than changing the data of file but still.
It's basically a classic TOCTOU race, tar needs to honor the EOF returned from read() as authoritative.
This is actually a very common trap for junior *nix programmers; treating stat() and a subsequent mmap() or read() loop as if they were atomic with regards to stat.st_size. The size returned by stat() can be used as an estimate, but otherwise can't be applied to subsequent operations.
https://unix.stackexchange.com/questions/333975/is-using-tar...
One of the first things I do when I download source code is decompress it and then de-archive it with GNU tar, then promptly re-archive it wit a real, AT&T UNIX System V 4.0 tar, because it's a known fact among us old UNIX folks that GNU tar is buggy as hell and only GNU tar can correctly read GNU tar (that wasn't the point of a tape archiver, but GNU people didn't get that memo).
Additionally, any true System V UNIX like IRIX and HP-UX will have it.
One can check the problems he noticed in gnu tar implementation in the readme file of his start project:
https://sourceforge.net/projects/s-tar/files/README.otherbug...
But note that the last version of star was released in 2008 and README.otherbugs file is actually from 2001.
[1] https://sourceforge.net/projects/s-tar [2] https://en.wikipedia.org/wiki/Tar_(computing)#Key_implementa...
Such posts have in the past been super helpful for me personally (and to others I imagine), in going from plain weeping that stuff just randomly breaks, to learning to enjoy examining the possible causes and understanding how to explain the problem concisely and with enough detail to make it useful to a developer.
He’ll be able to reuse much of his blog post in an great bug report with easy steps to reproduce the problem, excepted and actual outcomes of following those steps, and a scenario where it will happen in real deployments as well as a providing a workaround.