summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--src/tac.c6
-rwxr-xr-xtests/misc/tac6
3 files changed, 13 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 93a1f96b4..3eb28b1e3 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ GNU coreutils NEWS -*- outline -*-
du -H and -L now consistently count pointed-to files instead of
symbolic links, and correctly diagnose dangling symlinks.
+ tac would perform a double-free when given an input line longer than 16KiB.
+ [bug introduced in coreutils-8.3]
+
** New features
cp now accepts the --attributes-only option to not copy file data,
diff --git a/src/tac.c b/src/tac.c
index cec973601..859e0067a 100644
--- a/src/tac.c
+++ b/src/tac.c
@@ -633,7 +633,6 @@ main (int argc, char **argv)
if (! (read_size < half_buffer_size && half_buffer_size < G_buffer_size))
xalloc_die ();
G_buffer = xmalloc (G_buffer_size);
- void *buf = G_buffer;
if (sentinel_length)
{
strcpy (G_buffer, separator);
@@ -666,6 +665,9 @@ main (int argc, char **argv)
error (0, errno, "-");
ok = false;
}
- free (buf);
+
+ size_t offset = sentinel_length ? sentinel_length : 1;
+ free (G_buffer - offset);
+
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/tests/misc/tac b/tests/misc/tac
index 763104993..4130c004d 100755
--- a/tests/misc/tac
+++ b/tests/misc/tac
@@ -24,6 +24,9 @@ my $prog = 'tac';
my $bad_dir = 'no/such/dir';
+# This must be longer than 16KiB to trigger the double free in coreutils-8.5.
+my $long_line = 'o' x (16 * 1024 + 1);
+
my @Tests =
(
['segfault', '-r', {IN=>"a\n"}, {IN=>"b\n"}, {OUT=>"a\nb\n"}],
@@ -67,6 +70,9 @@ my @Tests =
{ERR_SUBST => "s,`$bad_dir': .*,...,"},
{ERR => "$prog: cannot create temporary file in ...\n"},
{EXIT => 1}],
+
+ # coreutils-8.5's tac would double-free its primary buffer.
+ ['double-free', {IN=>$long_line}, {OUT=>$long_line}],
);
@Tests = triple_test \@Tests;