summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2016-11-27 15:09:53 +0000
committerPádraig Brady <P@draigBrady.com>2016-11-28 13:19:24 +0000
commita39641cbb8f37c5a19dd4820c6f6719c82d3e633 (patch)
treeee662cfc8add8265c1de488a9d281eba21c9d8a4 /src
parent6f30a99fa537adb029283cf2ef03cb4419350e6c (diff)
downloadcoreutils-a39641cbb8f37c5a19dd4820c6f6719c82d3e633.tar.xz
tac: fix mem corruption when failing to read non seekable inputs
This was detected with ASAN, but can also be seen without ASAN with: $ tac - - <&- tac: standard input: read error: Bad file descriptor *** Error in `tac': malloc(): memory corruption: 0x... * src/tac.c (copy_to_temp): Don't close our output stream on (possibly transient) output error, or on input error. (temp_stream): clearerr() on the stream about to be reused, to ensure future stream use is not impacted by transient errors. * tests/misc/tac-2-nonseekable.sh: Add a test case. * NEWS: Mention the bug fix. Fixes http://bugs.gnu.org/25041
Diffstat (limited to 'src')
-rw-r--r--src/tac.c11
1 files changed, 4 insertions, 7 deletions
diff --git a/src/tac.c b/src/tac.c
index 2e820fa07..c1b6003da 100644
--- a/src/tac.c
+++ b/src/tac.c
@@ -477,6 +477,7 @@ temp_stream (FILE **fp, char **file_name)
}
else
{
+ clearerr (tmp_fp);
if (fseeko (tmp_fp, 0, SEEK_SET) < 0
|| ftruncate (fileno (tmp_fp), 0) < 0)
{
@@ -512,13 +513,13 @@ copy_to_temp (FILE **g_tmp, char **g_tempfile, int input_fd, char const *file)
if (bytes_read == SAFE_READ_ERROR)
{
error (0, errno, _("%s: read error"), quotef (file));
- goto Fail;
+ return -1;
}
if (fwrite (G_buffer, 1, bytes_read, fp) != bytes_read)
{
error (0, errno, _("%s: write error"), quotef (file_name));
- goto Fail;
+ return -1;
}
/* Implicitly <= OFF_T_MAX due to preceding fwrite(),
@@ -530,16 +531,12 @@ copy_to_temp (FILE **g_tmp, char **g_tempfile, int input_fd, char const *file)
if (fflush (fp) != 0)
{
error (0, errno, _("%s: write error"), quotef (file_name));
- goto Fail;
+ return -1;
}
*g_tmp = fp;
*g_tempfile = file_name;
return bytes_copied;
-
- Fail:
- fclose (fp);
- return -1;
}
/* Copy INPUT_FD to a temporary, then tac that file.