Re: UBSAN report for main [so: 14] /usr/bin/whatis: non-zero (48) and zero offsets from null pointer in qsort.c

From: Stefan Esser <se_at_FreeBSD.org>
Date: Tue, 11 Jan 2022 13:19:09 UTC
Am 11.01.22 um 08:40 schrieb Mark Millard:
> # whatis dog
> /usr/main-src/lib/libc/stdlib/qsort.c:114:23: runtime error: applying non-zero offset 48 to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdlib/qsort.c:114:23 in 
> /usr/main-src/lib/libc/stdlib/qsort.c:114:44: runtime error: applying zero offset to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/main-src/lib/libc/stdlib/qsort.c:114:44 in 
> whatis: nothing appropriate
> 
> This seems to be only for the not-found case.
> 
> ===
> Mark Millard
> marklmi at yahoo.com

The undefined behavior is caused by insufficient checking of parameters
in mansearch.c.

As part of the initializations performed at the start of mansearch(),
the variables cur and *res are initialized to 0 resp. NULL:

	cur = maxres = 0;	
	if (res != NULL)
		*res = NULL;

If no match is found, these values are unchanged at line 223, where res
is checked to be non-NULL, but then *res is passed to qsort() and that
is still NULL.

Suggested fix (also attached to avoid white-space issues):

--- usr.bin/mandoc/mansearch.c
+++ usr.bin/mandoc/mansearch.c
@@ -220,7 +220,7 @@
 	if (cur && search->firstmatch)
 		break;
 	}
-	if (res != NULL)
+	if (res != NULL && *res != NULL)
 		qsort(*res, cur, sizeof(struct manpage), manpage_compare);
 	if (chdir_status && getcwd_status && chdir(buf) == -1)
 		warn("%s", buf);

(File name as in OpenBSD, it is contrib/mandoc/mansearch.c in FreeBSD.)

Regards, STefan