diff options
Diffstat (limited to 'lib/libc/stdio/fread.c')
-rw-r--r-- | lib/libc/stdio/fread.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 6253856..ad3ea29 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include <errno.h> +#include <stdint.h> #include <stdio.h> #include <string.h> #include "un-namespace.h" @@ -69,8 +71,27 @@ __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ - if ((resid = count * size) == 0) + if ((count == 0) || (size == 0)) return (0); + + /* + * Check for integer overflow. As an optimization, first check that + * at least one of {count, size} is at least 2^16, since if both + * values are less than that, their product can't possible overflow + * (size_t is always at least 32 bits on FreeBSD). + */ + if (((count | size) > 0xFFFF) && + (count > SIZE_MAX / size)) { + errno = EINVAL; + fp->_flags |= __SERR; + return (0); + } + + /* + * Compute the (now required to not overflow) number of bytes to + * read and actually do the work. + */ + resid = count * size; ORIENT(fp, -1); if (fp->_r < 0) fp->_r = 0; |