Avoid undefined behavior in fread(3)

On the first call to fread(3), just after fopen(3) the internal buffers
are empty. This means that _r and _p (among others) are zeroed.

Passing NULL to the 2nd argument of memcpy(3) for the zero length is
undefined. Calling _p += 0 triggers LLVM UBSan (NULL pointer arithmetic).
Calling _p += 0, p += 0 and resid -= 0 has no effect.

Replace the "fp->_r = 0;" logic with a short circuit jump to __srefill()
that sets _r internally and refills the FILE buffers.

No functional change from an end user point of view, except skipping a few
dummy operations on the first call, for a FILE pointer, to fread(3).
This commit is contained in:
kamil 2020-02-22 22:02:46 +00:00
parent e6cc2fd8f9
commit 6f201b686b
1 changed files with 9 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fread.c,v 1.22 2012/03/15 18:22:30 christos Exp $ */
/* $NetBSD: fread.c,v 1.23 2020/02/22 22:02:46 kamil Exp $ */
/*-
* Copyright (c) 1990, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93";
#else
__RCSID("$NetBSD: fread.c,v 1.22 2012/03/15 18:22:30 christos Exp $");
__RCSID("$NetBSD: fread.c,v 1.23 2020/02/22 22:02:46 kamil Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@ -68,16 +68,21 @@ fread(void *buf, size_t size, size_t count, FILE *fp)
_DIAGASSERT(buf != NULL);
FLOCKFILE(fp);
if (fp->_r < 0)
fp->_r = 0;
total = resid;
p = buf;
if (fp->_r <= 0) {
/* Nothing to read on enter, refill the buffers. */
goto refill;
}
while (resid > (size_t)(r = fp->_r)) {
(void)memcpy(p, fp->_p, (size_t)r);
fp->_p += r;
/* fp->_r = 0 ... done in __srefill */
p += r;
resid -= r;
refill:
if (__srefill(fp)) {
/* no more input: return partial result */
FUNLOCKFILE(fp);