Subject: Patch for snprintf/vsnprintf bugs.
To: None <tech-userlevel@netbsd.org>
From: Krister Walfridsson <cato@df.lth.se>
List: tech-userlevel
Date: 01/04/2003 21:53:14
There are two rather serious (IMHO) bugs in snprintf/vsnprintf.

1. snprintf(foo, 0. "XXX") is guaranteed not to write in foo by the
   standard (ISO/IEC 9899 7.19.6.5) but our implementation handles this
   as if the buffer has a size of (size_t)-1.

2. snprintf(NULL, 0, "XXX") leaks memory since cantwrite() allocates
   memory if _bf._base == NULL, and this buffer is never freed
   (PR 16483).

I have solved this by adding a dummy buffer for the cases when the
functions don't get a buffer it may write in.

OK to commit?

   /Krister



Index: stdio/snprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/snprintf.c,v
retrieving revision 1.16
diff -u -r1.16 snprintf.c
--- stdio/snprintf.c	2002/05/26 14:44:00	1.16
+++ stdio/snprintf.c	2003/01/04 20:36:47
@@ -65,6 +65,7 @@
 	va_list ap;
 	FILE f;
 	struct __sfileext fext;
+	unsigned char dummy[1];

 	_DIAGASSERT(n == 0 || str != NULL);
 	_DIAGASSERT(fmt != NULL);
@@ -77,8 +78,16 @@
 	_FILEEXT_SETUP(&f, &fext);
 	f._file = -1;
 	f._flags = __SWR | __SSTR;
-	f._bf._base = f._p = (unsigned char *)str;
-	f._bf._size = f._w = n - 1;
+	if (n == 0)
+	{
+		f._bf._base = f._p = dummy;
+		f._bf._size = f._w = 0;
+	}
+	else
+	{
+		f._bf._base = f._p = (unsigned char *)str;
+		f._bf._size = f._w = n - 1;
+	}
 	ret = vfprintf(&f, fmt, ap);
 	*f._p = 0;
 	va_end(ap);
Index: stdio/vsnprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/vsnprintf.c,v
retrieving revision 1.16
diff -u -r1.16 vsnprintf.c
--- stdio/vsnprintf.c	2001/12/07 11:47:45	1.16
+++ stdio/vsnprintf.c	2003/01/04 20:36:47
@@ -66,6 +66,7 @@
 	int ret;
 	FILE f;
 	struct __sfileext fext;
+	unsigned char dummy[1];

 	_DIAGASSERT(n == 0 || str != NULL);
 	_DIAGASSERT(fmt != NULL);
@@ -78,8 +79,16 @@
 	_FILEEXT_SETUP(&f, &fext);
 	f._file = -1;
 	f._flags = __SWR | __SSTR;
-	f._bf._base = f._p = (unsigned char *)str;
-	f._bf._size = f._w = n - 1;
+	if (n == 0)
+	{
+		f._bf._base = f._p = dummy;
+		f._bf._size = f._w = 0;
+	}
+	else
+	{
+		f._bf._base = f._p = (unsigned char *)str;
+		f._bf._size = f._w = n - 1;
+	}
 	ret = vfprintf(&f, fmt, ap);
 	*f._p = 0;
 	return (ret);