Module Name:    src
Committed By:   riastradh
Date:           Sat Aug 12 12:48:37 UTC 2023

Modified Files:
        src/lib/libc/gen: vis.c
        src/tests/lib/libc/gen: t_vis.c

Log Message:
vis(3): Fix main part of PR lib/57573.

>From Kyle Evans <kev...@freebsd.org>.

XXX pullup-10
XXX pullup-9
XXX pullup-8


To generate a diff of this commit:
cvs rdiff -u -r1.81 -r1.82 src/lib/libc/gen/vis.c
cvs rdiff -u -r1.12 -r1.13 src/tests/lib/libc/gen/t_vis.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/gen/vis.c
diff -u src/lib/libc/gen/vis.c:1.81 src/lib/libc/gen/vis.c:1.82
--- src/lib/libc/gen/vis.c:1.81	Sat Aug 12 12:48:17 2023
+++ src/lib/libc/gen/vis.c	Sat Aug 12 12:48:37 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: vis.c,v 1.81 2023/08/12 12:48:17 riastradh Exp $	*/
+/*	$NetBSD: vis.c,v 1.82 2023/08/12 12:48:37 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1989, 1993
@@ -57,7 +57,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: vis.c,v 1.81 2023/08/12 12:48:17 riastradh Exp $");
+__RCSID("$NetBSD: vis.c,v 1.82 2023/08/12 12:48:37 riastradh Exp $");
 #endif /* LIBC_SCCS and not lint */
 #ifdef __FBSDID
 __FBSDID("$FreeBSD$");
@@ -396,13 +396,14 @@ static int
 istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
     int flags, const char *mbextra, int *cerr_ptr)
 {
+	char mbbuf[MB_LEN_MAX];
 	wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
 	size_t len, olen;
 	uint64_t bmsk, wmsk;
 	wint_t c;
 	visfun_t f;
 	int clen = 0, cerr, error = -1, i, shft;
-	char *mbdst, *mdst;
+	char *mbdst, *mbwrite, *mdst;
 	size_t mbslength;
 	size_t maxolen;
 	mbstate_t mbstate;
@@ -579,8 +580,33 @@ istrsenvisx(char **mbdstp, size_t *dlen,
 	olen = 0;
 	memset(&mbstate, 0, sizeof(mbstate));
 	for (dst = start; len > 0; len--) {
-		if (!cerr)
-			clen = wcrtomb(mbdst, *dst, &mbstate);
+		if (!cerr) {
+			/*
+			 * If we have at least MB_CUR_MAX bytes in the buffer,
+			 * we'll just do the conversion in-place into mbdst.  We
+			 * need to be a little more conservative when we get to
+			 * the end of the buffer, as we may not have MB_CUR_MAX
+			 * bytes but we may not need it.
+			 */
+			if (maxolen - olen > MB_CUR_MAX)
+				mbwrite = mbdst;
+			else
+				mbwrite = mbbuf;
+			clen = wcrtomb(mbwrite, *dst, &mbstate);
+			if (clen > 0 && mbwrite != mbdst) {
+				/*
+				 * Don't break past our output limit, noting
+				 * that maxolen includes the nul terminator so
+				 * we can't write past maxolen - 1 here.
+				 */
+				if (olen + clen >= maxolen) {
+					errno = ENOSPC;
+					goto out;
+				}
+
+				memcpy(mbdst, mbwrite, clen);
+			}
+		}
 		if (cerr || clen < 0) {
 			/*
 			 * Conversion error, process as a byte(s) instead.
@@ -595,16 +621,27 @@ istrsenvisx(char **mbdstp, size_t *dlen,
 				shft = i * NBBY;
 				bmsk = (uint64_t)0xffLL << shft;
 				wmsk |= bmsk;
-				if ((*dst & wmsk) || i == 0)
+				if ((*dst & wmsk) || i == 0) {
+					if (olen + clen + 1 >= maxolen) {
+						errno = ENOSPC;
+						goto out;
+					}
+
 					mbdst[clen++] = (char)(
 					    (uint64_t)(*dst & bmsk) >>
 					    shft);
+				}
 			}
 			cerr = 1;
 		}
-		/* If this character would exceed our output limit, stop. */
-		if (olen + clen > maxolen)
-			break;
+
+		/*
+		 * We'll be dereferencing mbdst[clen] after this to write the
+		 * nul terminator; the above paths should have checked for a
+		 * possible overflow already.
+		 */
+		assert(olen + clen < maxolen);
+
 		/* Advance output pointer by number of bytes written. */
 		mbdst += clen;
 		/* Advance buffer character pointer. */

Index: src/tests/lib/libc/gen/t_vis.c
diff -u src/tests/lib/libc/gen/t_vis.c:1.12 src/tests/lib/libc/gen/t_vis.c:1.13
--- src/tests/lib/libc/gen/t_vis.c:1.12	Sat Aug 12 12:46:16 2023
+++ src/tests/lib/libc/gen/t_vis.c	Sat Aug 12 12:48:37 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_vis.c,v 1.12 2023/08/12 12:46:16 riastradh Exp $	*/
+/*	$NetBSD: t_vis.c,v 1.13 2023/08/12 12:48:37 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -211,8 +211,6 @@ ATF_TC_BODY(strvis_overflow_mb, tc)
 	unsigned i;
 	int n;
 
-	atf_tc_expect_fail("PR lib/57573: Overflow possibilities in vis(3)");
-
 	setlocale(LC_CTYPE, "en_US.UTF-8");
 
 	for (i = 0; i < sizeof(dst) - 1; i++) {
@@ -251,8 +249,6 @@ ATF_TC_BODY(strvis_overflow_c, tc)
 	unsigned i;
 	int n;
 
-	atf_tc_expect_fail("PR lib/57573: Overflow possibilities in vis(3)");
-
 	for (i = 0; i < sizeof(dst) - 1; i++) {
 		memset(dst, STRVIS_OVERFLOW_MARKER, sizeof(dst));
 		n = strnvis(dst, i, src, VIS_SAFE | VIS_NOLOCALE);

Reply via email to