Skip to content

tac: use temp file for stdin to respect TMPDIR and handle disk-full errors#10094

Merged
sylvestre merged 3 commits into
uutils:mainfrom
ChrisDryden:tac-stdin-tempfile
Jan 9, 2026
Merged

tac: use temp file for stdin to respect TMPDIR and handle disk-full errors#10094
sylvestre merged 3 commits into
uutils:mainfrom
ChrisDryden:tac-stdin-tempfile

Conversation

@ChrisDryden

@ChrisDryden ChrisDryden commented Jan 6, 2026

Copy link
Copy Markdown
Collaborator

The tac-continue test used to rely on having an accessible TMP_DIR, the test was changed and now it was updated to be more flexible. Ultimately the functionality of tac in our implementation compared to the GNU implementation was just different from the context that the stdin is buffered to a TMP_DIR in the GNU implementation and not in the uutils implementation. This can cause issues with large STDIN because it will always max out the memory and timeout instead of erroring and it takes up significantly more memory.

@github-actions

github-actions Bot commented Jan 7, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

GNU test failed: tests/tac/tac. tests/tac/tac is passing on 'main'. Maybe you have to rebase?

@github-actions

github-actions Bot commented Jan 7, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Congrats! The gnu test tests/tac/tac-continue is now passing!

@ChrisDryden
ChrisDryden marked this pull request as ready for review January 7, 2026 01:09
Comment thread src/uu/tac/src/tac.rs Outdated
@codspeed-hq

codspeed-hq Bot commented Jan 7, 2026

Copy link
Copy Markdown

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing ChrisDryden:tac-stdin-tempfile (fbec632) with main (6d1df56)

Summary

✅ 142 untouched benchmarks
⏩ 37 skipped benchmarks1

Footnotes

  1. 37 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@github-actions

github-actions Bot commented Jan 7, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skipping an intermittent issue tests/tty/tty-eof (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/tac/tac-continue is now passing!

@ChrisDryden

Copy link
Copy Markdown
Collaborator Author

Promise I'm not just rebasing for the sake of rebasing, all of the ones I've rebased right now all have merge conflicts that I'm sorting out

@github-actions

github-actions Bot commented Jan 9, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skipping an intermittent issue tests/shuf/shuf-reservoir (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/sort/sort-stale-thread-mem (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/tac/tac-continue is now passing!

@sylvestre
sylvestre merged commit b5a49f3 into uutils:main Jan 9, 2026
134 checks passed
Comment thread util/fetch-gnu.sh
curl -L ${repo}/raw/refs/heads/master/tests/runcon/runcon-compute.sh > tests/runcon/runcon-compute.sh
curl -L ${repo}/raw/refs/heads/master/tests/tac/tac-continue.sh > tests/tac/tac-continue.sh
# Add tac-continue.sh to root tests (it requires root to mount tmpfs)
sed -i 's|tests/split/l-chunk-root.sh.*|tests/split/l-chunk-root.sh\t\t\t\\\n tests/tac/tac-continue.sh\t\t\t\\|' tests/local.mk

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sed -i does not work on macOS. So I changed it to -i.bak at #10201

DarthStrom added a commit to DarthStrom/coreutils that referenced this pull request Jun 20, 2026
tac memory-mapped regular files. If another process truncated such a
file while it was mapped (e.g. during log rotation), accessing the
now-invalid pages raised SIGBUS and killed the process. Read regular
files into memory up front instead, so a concurrent truncation can no
longer crash tac.

The stdin path had the same hole by a different route: `tac < file`
mapped the raw stdin fd -- the caller's regular file -- directly. Remove
that direct-stdin mmap and always route stdin through a process-owned
temp file (already used to bound memory on large stdin, see uutils#10094).
The temp file is created unlinked, so no other process can truncate it
and mapping it stays sound.

Adds regression tests that truncate a file mid-read, via both an
argument and stdin redirection, and assert tac is not killed by a
signal.

Fixes uutils#9748

Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Charlie Tonneslan <cst0520@gmail.com>
DarthStrom added a commit to DarthStrom/coreutils that referenced this pull request Jun 21, 2026
tac memory-mapped regular files. If another process truncated such a
file while it was mapped (e.g. during log rotation), accessing the
now-invalid pages raised SIGBUS and killed the process. Read regular
files into memory up front instead, so a concurrent truncation can no
longer crash tac.

The stdin path had the same hole by a different route: `tac < file`
mapped the raw stdin fd -- the caller's regular file -- directly. Remove
that direct-stdin mmap and always route stdin through a process-owned
temp file (already used to bound memory on large stdin, see uutils#10094).
The temp file is created unlinked, so no other process can truncate it
and mapping it stays sound.

Adds regression tests that truncate a file mid-read, via both an
argument and stdin redirection, and assert tac is not killed by a
signal.

Fixes uutils#9748

Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Charlie Tonneslan <cst0520@gmail.com>
DarthStrom added a commit to DarthStrom/coreutils that referenced this pull request Jul 3, 2026
tac memory-mapped regular files. If another process truncated such a
file while it was mapped (e.g. during log rotation), accessing the
now-invalid pages raised SIGBUS and killed the process. Read regular
files into memory up front instead, so a concurrent truncation can no
longer crash tac.

The stdin path had the same hole by a different route: `tac < file`
mapped the raw stdin fd -- the caller's regular file -- directly. Remove
that direct-stdin mmap and always route stdin through a process-owned
temp file (already used to bound memory on large stdin, see uutils#10094).
The temp file is created unlinked, so no other process can truncate it
and mapping it stays sound.

Adds regression tests that truncate a file mid-read, via both an
argument and stdin redirection, and assert tac is not killed by a
signal.

Fixes uutils#9748

Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Charlie Tonneslan <cst0520@gmail.com>
DarthStrom added a commit to DarthStrom/coreutils that referenced this pull request Jul 3, 2026
tac memory-mapped regular files. If another process truncated such a
file while it was mapped (e.g. during log rotation), accessing the
now-invalid pages raised SIGBUS and killed the process. Read regular
files into memory up front instead, so a concurrent truncation can no
longer crash tac.

The stdin path had the same hole by a different route: `tac < file`
mapped the raw stdin fd -- the caller's regular file -- directly. Remove
that direct-stdin mmap and always route stdin through a process-owned
temp file (already used to bound memory on large stdin, see uutils#10094).
The temp file is created unlinked, so no other process can truncate it
and mapping it stays sound.

Adds regression tests that truncate a file mid-read, via both an
argument and stdin redirection, and assert tac is not killed by a
signal.

Fixes uutils#9748

Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Charlie Tonneslan <cst0520@gmail.com>
DarthStrom added a commit to DarthStrom/coreutils that referenced this pull request Jul 3, 2026
tac memory-mapped regular files. If another process truncated such a
file while it was mapped (e.g. during log rotation), accessing the
now-invalid pages raised SIGBUS and killed the process. Read regular
files into memory up front instead, so a concurrent truncation can no
longer crash tac.

The stdin path had the same hole by a different route: `tac < file`
mapped the raw stdin fd -- the caller's regular file -- directly. Remove
that direct-stdin mmap and always route stdin through a process-owned
temp file (already used to bound memory on large stdin, see uutils#10094).
The temp file is created unlinked, so no other process can truncate it
and mapping it stays sound.

Adds regression tests that truncate a file mid-read, via both an
argument and stdin redirection, and assert tac is not killed by a
signal.

Fixes uutils#9748

Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Charlie Tonneslan <cst0520@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants