diff options
author | Pádraig Brady <P@draigBrady.com> | 2013-01-23 12:34:46 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2013-04-14 01:01:21 +0100 |
commit | 1fe218888aace1703f78e0af0059d7a15485bf7f (patch) | |
tree | 814d8ed411722cf1bb074fe5be861a4e4c7c9d6c /src | |
parent | 8901e010fa24ba375d53e3e37fc7819621adcf19 (diff) | |
download | coreutils-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.c | 28 |
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); |