* lib/extendbuf.c (xextendbuf): New function; extends the buffer, but calls xalloc_die on failure. On the the other hand, extendbuf returns NULL on failure. (decide_size): If wanted>SIZE_MAX/2, return wanted. This means that for very large buffers, performance on repeated extension degrades from linear to quadratic (instead of just failing at that point, as before). * lib/savedirinfo.c (xsavedir): Use xextendbuf rather than extendbuf, now that there is a difference in semantics. * find/fstype.c (get_mounted_filesystems): If extendbuf returns NULL, fail (by returning NULL ourselves). (get_mounted_devices): Likewise.
Signed-off-by: James Youngman <j...@gnu.org> --- ChangeLog | 16 ++++++++++++++++ find/fstype.c | 37 +++++++++++++++++++++++++++++-------- lib/extendbuf.c | 27 ++++++++++++++++++++++----- lib/extendbuf.h | 1 + lib/savedirinfo.c | 6 +++--- 5 files changed, 71 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 709235a..3035d74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2010-04-05 James Youngman <j...@gnu.org> + + Support extendbuf buffers larger than SIZE_MAX/2. + * lib/extendbuf.c (xextendbuf): New function; extends the buffer, + but calls xalloc_die on failure. On the the other hand, extendbuf + returns NULL on failure. + (decide_size): If wanted>SIZE_MAX/2, return wanted. This means + that for very large buffers, performance on repeated extension + degrades from linear to quadratic (instead of just failing at that + point, as before). + * lib/savedirinfo.c (xsavedir): Use xextendbuf rather than + extendbuf, now that there is a difference in semantics. + * find/fstype.c (get_mounted_filesystems): If extendbuf returns + NULL, fail (by returning NULL ourselves). + (get_mounted_devices): Likewise. + 2010-04-04 James Youngman <j...@gnu.org> Fix Savannah bug #29435: fd_is_cloexec does not work on Fedora diff --git a/find/fstype.c b/find/fstype.c index 21c446b..dc96068 100644 --- a/find/fstype.c +++ b/find/fstype.c @@ -258,6 +258,7 @@ get_mounted_filesystems (void) size_t alloc_size = 0u; size_t used = 0u; struct mount_entry *entries, *entry; + void *p; entries = must_read_fs_list (false); for (entry=entries; entry; entry=entry->me_next) @@ -271,9 +272,17 @@ get_mounted_filesystems (void) set_fstype_devno (entry); len = strlen (entry->me_mountdir) + 1; - result = extendbuf (result, used+len, &alloc_size); - strcpy (&result[used], entry->me_mountdir); - used += len; /* len already includes one for the \0 */ + p = extendbuf (result, used+len, &alloc_size); + if (p) + { + result = p; + strcpy (&result[used], entry->me_mountdir); + used += len; /* len already includes one for the \0 */ + } + else + { + break; + } } free_file_system_list (entries); @@ -299,13 +308,25 @@ get_mounted_devices (size_t *n) entry; entry = entry->me_next) { - result = extendbuf (result, sizeof(dev_t)*(used+1), &alloc_size); - set_fstype_devno (entry); - result[used] = entry->me_dev; - ++used; + void *p = extendbuf (result, sizeof(dev_t)*(used+1), &alloc_size); + if (p) + { + result = p; + set_fstype_devno (entry); + result[used] = entry->me_dev; + ++used; + } + else + { + free (result); + result = NULL; + } } free_file_system_list (entries); - *n = used; + if (result) + { + *n = used; + } return result; } diff --git a/lib/extendbuf.c b/lib/extendbuf.c index e5aa074..6cc52d5 100644 --- a/lib/extendbuf.c +++ b/lib/extendbuf.c @@ -49,7 +49,7 @@ decide_size (size_t current, size_t wanted) while (newsize < wanted) { if (2 * newsize < newsize) - xalloc_die (); + return wanted; newsize *= 2; } return newsize; @@ -76,15 +76,18 @@ extendbuf (void* existing, size_t wanted, size_t *allocated) assert (NULL == existing); (*allocated) = newsize; - result = xmalloc (newsize); + result = malloc (newsize); } else { if (newsize != (*allocated) ) { (*allocated) = newsize; - result = xrealloc (existing, newsize); - + result = realloc (existing, newsize); + if (NULL == result) + { + saved_errno = errno; + } } else { @@ -94,10 +97,24 @@ extendbuf (void* existing, size_t wanted, size_t *allocated) if (result) { - /* xmalloc () or xrealloc () may have changed errno, but in the + /* malloc () or realloc () may have changed errno, but in the success case we want to preserve the previous value. */ errno = saved_errno; } return result; } + + +void * +xextendbuf (void* existing, size_t wanted, size_t *allocated) +{ + void *p = extendbuf (existing, wanted, allocated); + if (NULL == p) + { + free (existing); + xalloc_die (); + } + return p; +} + diff --git a/lib/extendbuf.h b/lib/extendbuf.h index 23a9e33..8d495a6 100644 --- a/lib/extendbuf.h +++ b/lib/extendbuf.h @@ -20,6 +20,7 @@ #define INC_EXTENDBUF_H 1 void *extendbuf(void* existing, size_t wanted, size_t *allocated); +void *xextendbuf(void* existing, size_t wanted, size_t *allocated); #endif diff --git a/lib/savedirinfo.c b/lib/savedirinfo.c index 631c038..62bc36b 100644 --- a/lib/savedirinfo.c +++ b/lib/savedirinfo.c @@ -189,11 +189,11 @@ xsavedir (const char *dir, int flags) { /* Remember the name. */ size_t entry_size = strlen (entry) + 1; - result->buffer = extendbuf (result->buffer, namebuf_used+entry_size, &namebuf_allocated); + result->buffer = xextendbuf (result->buffer, namebuf_used+entry_size, &namebuf_allocated); memcpy ((result->buffer) + namebuf_used, entry, entry_size); /* Remember the other stuff. */ - internal = extendbuf (internal, (1+result->size)*sizeof (*internal), &entrybuf_allocated); + internal = xextendbuf (internal, (1+result->size)*sizeof (*internal), &entrybuf_allocated); internal[result->size].flags = 0; #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE @@ -211,7 +211,7 @@ xsavedir (const char *dir, int flags) } } - result->buffer = extendbuf (result->buffer, namebuf_used+1, &namebuf_allocated); + result->buffer = xextendbuf (result->buffer, namebuf_used+1, &namebuf_allocated); result->buffer[namebuf_used] = '\0'; /* convert the result to its externally-usable form. */ -- 1.7.0 _______________________________________________ Findutils-patches mailing list Findutils-patches@gnu.org http://lists.gnu.org/mailman/listinfo/findutils-patches