Re: FYI: An example type of UBSAN failure during kyua test -k /usr/tests/Kyuafile

From: Stefan Esser <se_at_FreeBSD.org>
Date: Fri, 07 Jan 2022 12:31:10 UTC
Am 07.01.22 um 12:49 schrieb Mark Millard:
> Having done a buildworld with both WITH_ASAN= and WITH_UBSAN=
> after finding what to control to allow the build, I installed
> it in a directory tree for chroot use and have
> "kyua test -k /usr/tests/Kyuafile" running.
> 
> I see evidence of various examples of one type of undefined
> behavior: "applying zero offset to null pointer"
> 
> # more /usr/obj/DESTDIRs/main-amd64-xSAN-chroot/tmp/kyua.FKD2vh/356/stderr.txt 
> /usr/main-src/lib/libc/stdio/fread.c:133:10: runtime error: applying zero offset to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdio/fread.c:133:10 in 
> /usr/main-src/lib/libc/stdio/fread.c:133:10: runtime error: applying zero offset to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdio/fread.c:133:10 in 
> /usr/main-src/usr.bin/sed/process.c:715:18: runtime error: applying zero offset to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/usr.bin/sed/process.c:715:18 in 
> /usr/main-src/lib/libc/stdio/fread.c:133:10: runtime error: applying zero offset to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdio/fread.c:133:10 in 
> Fail: stderr not empty
> --- /dev/null   2022-01-07 10:29:57.182903000 +0000
> +++ /tmp/kyua.FKD2vh/356/work/check.Mk9llD/stderr       2022-01-07 10:29:57.173100000 +0000
> @@ -0,0 +1,2 @@
> +/usr/main-src/lib/libc/stdio/fread.c:133:10: runtime error: applying zero offset to null pointer
> +SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdio/fread.c:133:10 in 
> Files left in work directory after failure: mntpt, mounterr
> 
> 
> In general the lib/libc/stdio/fread.c:133:10 example seems to
> be in a place that would make it fairly common.

Interesting find:

        while (resid > (r = fp->_r)) {
                (void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
                fp->_p += r; /* line 133 */
                /* fp->_r = 0 ... done in __srefill */
                p += r;
                resid -= r;

If fp->_p == NULL in line 133, then NULL has been passed as source address
in memcpy() in the line above, and I'd think that is undefined behavior,
even if a length of 0 is passed at the same time.

Maybe the code block quoted above (line 132 to 136) should be made wrapped
into "if (r > 0) {}"?

Regards, STefan