diff options
author | 2007-06-26 05:00:50 +0000 | |
---|---|---|
committer | 2007-06-26 05:00:50 +0000 | |
commit | 57f92aee30215dd5a0f1b8c6304daafd65a90ac2 (patch) | |
tree | f11f3387116bbee98e802ae40eba9ffb22d26c4e /lib/libc | |
parent | add support for cvs rlog. (diff) | |
download | wireguard-openbsd-57f92aee30215dd5a0f1b8c6304daafd65a90ac2.tar.xz wireguard-openbsd-57f92aee30215dd5a0f1b8c6304daafd65a90ac2.zip |
It seems st_size is not always a good estimator for the number of
directory entries. ZFS, for instance, sets st_size to the number
of entries.
Use the same algorithm for the initial estimate but keep a minimum
to prevent a divide by zero. When the buffer is filled, instead
of re-using the same flawed algorithm, double the buffer size.
Also add check for integer overflow.
Bug reported by Ed Ravin, ZFS testing environment provided by Bryan
Allen.
OK millert
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/gen/scandir.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index f3b3fe2b569..089ad19e0da 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scandir.c,v 1.10 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: scandir.c,v 1.11 2007/06/26 05:00:50 ray Exp $ */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -35,7 +35,7 @@ * struct dirent (through namelist). Returns -1 if there were any errors. */ -#include <sys/types.h> +#include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <errno.h> @@ -73,8 +73,8 @@ scandir(const char *dirname, struct dirent ***namelist, * estimate the array size by taking the size of the directory file * and dividing it by a multiple of the minimum size entry. */ - arraysz = (stb.st_size / 24); - if (arraysz > SIZE_T_MAX / sizeof(struct dirent *)) { + arraysz = MAX(stb.st_size / 24, 16); + if (arraysz > SIZE_MAX / sizeof(struct dirent *)) { errno = ENOMEM; goto fail; } @@ -96,7 +96,9 @@ scandir(const char *dirname, struct dirent ***namelist, if (fstat(dirp->dd_fd, &stb) < 0) goto fail; - arraysz = stb.st_size / 12; + arraysz *= 2; + if (SIZE_MAX / sizeof(struct dirent *) < arraysz) + goto fail; nnames = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *)); if (nnames == NULL) |