summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2013-01-23 12:34:46 +0000
committerPádraig Brady <P@draigBrady.com>2013-04-14 01:01:21 +0100
commit1fe218888aace1703f78e0af0059d7a15485bf7f (patch)
tree814d8ed411722cf1bb074fe5be861a4e4c7c9d6c /src
parent8901e010fa24ba375d53e3e37fc7819621adcf19 (diff)
downloadcoreutils-1fe218888aace1703f78e0af0059d7a15485bf7f.tar.xz
head: with --bytes=-N only allocate memory as needed
* src/head.c (elide_tail_bytes_pipe): Don't use calloc as that bypasses memory overcommit due to the zeroing requirement. Also realloc rather than malloc the pointer array to avoid dependence on overcommit entirely. * tests/misc/head-c.sh: Add a test case. Fixes http://bugs.gnu.org/13530
Diffstat (limited to 'src')
-rw-r--r--src/head.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/src/head.c b/src/head.c
index d79d5f7de..00e1be17c 100644
--- a/src/head.c
+++ b/src/head.c
@@ -196,7 +196,7 @@ copy_fd (int src_fd, FILE *o_stream, uintmax_t n_bytes)
return COPY_FD_OK;
}
-/* Print all but the last N_ELIDE lines from the input available via
+/* Print all but the last N_ELIDE bytes from the input available via
the non-seekable file descriptor FD. Return true upon success.
Give a diagnostic and return false upon error. */
static bool
@@ -313,18 +313,34 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0)
size_t n_read;
bool buffered_enough;
size_t i, i_next;
- char **b;
+ char **b = NULL;
/* Round n_elide up to a multiple of READ_BUFSIZE. */
size_t rem = READ_BUFSIZE - (n_elide % READ_BUFSIZE);
size_t n_elide_round = n_elide + rem;
size_t n_bufs = n_elide_round / READ_BUFSIZE + 1;
- b = xcalloc (n_bufs, sizeof *b);
+ size_t n_alloc = 0;
+ size_t n_array_alloc = 0;
buffered_enough = false;
for (i = 0, i_next = 1; !eof; i = i_next, i_next = (i_next + 1) % n_bufs)
{
- if (b[i] == NULL)
- b[i] = xmalloc (READ_BUFSIZE);
+ if (n_array_alloc == i)
+ {
+ /* reallocate between 16 and n_bufs entries. */
+ if (n_array_alloc == 0)
+ n_array_alloc = MIN (n_bufs, 16);
+ else if (n_array_alloc <= n_bufs / 2)
+ n_array_alloc *= 2;
+ else
+ n_array_alloc = n_bufs;
+ b = xnrealloc (b, n_array_alloc, sizeof *b);
+ }
+
+ if (! buffered_enough)
+ {
+ b[i] = xmalloc (READ_BUFSIZE);
+ n_alloc = i + 1;
+ }
n_read = full_read (fd, b[i], READ_BUFSIZE);
if (n_read < READ_BUFSIZE)
{
@@ -388,7 +404,7 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0)
}
free_mem:
- for (i = 0; i < n_bufs; i++)
+ for (i = 0; i < n_alloc; i++)
free (b[i]);
free (b);