diff options
author | 2007-06-26 05:00:50 +0000 | |
---|---|---|
committer | 2007-06-26 05:00:50 +0000 | |
commit | 57f92aee30215dd5a0f1b8c6304daafd65a90ac2 (patch) | |
tree | f11f3387116bbee98e802ae40eba9ffb22d26c4e | |
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
-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) |