git: 977ed30681c3 - stable/13 - fread.c: fix undefined behavior
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 04 Mar 2022 19:48:18 UTC
The branch stable/13 has been updated by se: URL: https://cgit.FreeBSD.org/src/commit/?id=977ed30681c346a0b6be76a2e03b6651b94b58aa commit 977ed30681c346a0b6be76a2e03b6651b94b58aa Author: Stefan Eßer <se@FreeBSD.org> AuthorDate: 2022-01-15 23:30:04 +0000 Commit: Stefan Eßer <se@FreeBSD.org> CommitDate: 2022-03-04 19:47:23 +0000 fread.c: fix undefined behavior A case of undefined behavior in __fread() has been detected by UBSAN and reported by Mark Millard: /usr/main-src/lib/libc/stdio/fread.c:133:10: runtime error: applying zero offset to null pointer SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior in /usr/main-src/lib/libc/stdio/fread.c:133:10 While being benign (the NULL pointer is later passed to memcpy() with a length argument of 0), this issue causes in the order of 600 Kyua test cases to fail on systems running a world built with WITH_UBSAN and WITH_ASAN. The undefined behavior can be prevented by skipping operations that have no effect for r == 0. Mark Millard has suggested to only skip this code segment if fp->_p == NULL, but I have verified that for the case of r == 0 no further argument checking is performed on the addresses passed to memcpy() and thus no bugs are hidden from the sanitizers due to the simpler condition chosen. (cherry picked from commit 10af8e45a89818754b80315539e167ae49599f17) --- lib/libc/stdio/fread.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 11f8d13f0caf..cafe86fe7961 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -129,11 +129,13 @@ __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) } while (resid > (r = fp->_r)) { - (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); - fp->_p += r; - /* fp->_r = 0 ... done in __srefill */ - p += r; - resid -= r; + if (r != 0) { + (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); + fp->_p += r; + /* fp->_r = 0 ... done in __srefill */ + p += r; + resid -= r; + } if (__srefill(fp)) { /* no more input: return partial result */ return ((total - resid) / size);