Paul Eggert <egg...@cs.ucla.edu> writes: > It would be clearer without the casts. (Casts are often > overkill in C; they disable too much checking.) Also, I'm still > dubious about going ahead with a file that's too > large to fit into memory.
Here is another version, it fails with ENOMEM on files that don't fit into memory. Cheers, Giuseppe >From 985a52e1b654fa904e964977b24306fb97c586e7 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano <gscriv...@gnu.org> Date: Tue, 3 Aug 2010 15:40:19 +0200 Subject: [PATCH] read-file: Avoid memory reallocations with regular files. * modules/read-file (Depends-on): Add ftello and malloc-posix. * lib/read-file.c: Include <sys/types.h>, <sys/stat.h>, <unistd.h>, <stdio.h>, <stdint.h>. (fread_file): With regular files, use the remaining length as the initial buffer size. Check against overflow. --- ChangeLog | 9 +++++++++ lib/read-file.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- modules/read-file | 2 ++ 3 files changed, 57 insertions(+), 1 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d24a34..95b9fab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2010-08-03 Giuseppe Scrivano <gscriv...@gnu.org> + + read-file: Avoid memory reallocations with regular files. + * modules/read-file (Depends-on): Add ftello and malloc-posix. + * lib/read-file.c: Include <sys/types.h>, <sys/stat.h>, + <unistd.h>, <stdio.h>, <stdint.h>. + (fread_file): With regular files, use the remaining length as the + initial buffer size. Check against overflow. + 2010-08-01 Bruno Haible <br...@clisp.org> Integrate the regex documentation. diff --git a/lib/read-file.c b/lib/read-file.c index 6b655db..628def1 100644 --- a/lib/read-file.c +++ b/lib/read-file.c @@ -20,6 +20,17 @@ #include "read-file.h" +/* Get fstat. */ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +/* Get ftello. */ +#include <stdio.h> + +/* Get SIZE_MAX. */ +#include <stdint.h> + /* Get realloc, free. */ #include <stdlib.h> @@ -38,6 +49,33 @@ fread_file (FILE * stream, size_t * length) size_t alloc = 0; size_t size = 0; int save_errno; + struct stat st; + + do + { + off_t alloc_off, pos; + + if (fstat (fileno (stream), &st) < 0 || !S_ISREG (st.st_mode)) + break; + + pos = ftello (stream); + if (pos < 0 || pos > st.st_size) + break; + + alloc_off = st.st_size - pos; + if (SIZE_MAX <= alloc_off) + { + errno = ENOMEM; + return NULL; + } + + alloc = alloc_off + 1; + + buf = malloc (alloc); + if (!buf) + return NULL; + } + while (0); for (;;) { @@ -47,8 +85,15 @@ fread_file (FILE * stream, size_t * length) if (size + BUFSIZ + 1 > alloc) { char *new_buf; + size_t new_alloc = alloc + alloc / 2; + + if (new_alloc < alloc) + { + save_errno = ENOMEM; + break; + } - alloc += alloc / 2; + alloc = new_alloc; if (alloc < size + BUFSIZ + 1) alloc = size + BUFSIZ + 1; diff --git a/modules/read-file b/modules/read-file index e302940..64c1d63 100644 --- a/modules/read-file +++ b/modules/read-file @@ -7,6 +7,8 @@ lib/read-file.c m4/read-file.m4 Depends-on: +ftello +malloc-posix realloc-posix configure.ac: -- 1.7.1