[PATCH] check for broken snprintf + workaround

Oswald Buddenhagen ossi at kde.org
Mon Dec 9 13:21:29 GMT 2002


heya,

as a followup to my bitching about constructs like
  snprintf(buf, sizeof(buf) - 1, [...]);
  buf[sizeof(buf)-1] = 0;
all across the kde code i implemented a rather paranoid configure 
check + centralized this ugly workaround.
there are two known breakages:
* if snprintf overflows (like the linux libc4 libbsd one that simply
  calls sprintf) the test will bail.
* if snprintf does not null-terminate in the overflow case (like m$ vc++
  <= 6 - just in case the native windoze port becomes reality some day :),
  the calls are substituted with wrappers which add the null.

my only concern is the #define [v]snprintf that might collide with other
snprintfs than the libc one (too bad that c does not provide aliasing at
the language level). i know that sprintf would collide, but am not aware
of any snprintf()s - somebody?

at this occasion i also removed the old-style varargs stuff, as kde
won't run with it in any case.

greetings

-- 
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
--
Chaos, panic, and disorder - my work here is done.
-------------- next part --------------
Index: admin/acinclude.m4.in
===================================================================
RCS file: /home/kde/kde-common/admin/acinclude.m4.in,v
retrieving revision 2.306
diff -u -r2.306 acinclude.m4.in
--- admin/acinclude.m4.in	5 Dec 2002 20:30:26 -0000	2.306
+++ admin/acinclude.m4.in	9 Dec 2002 12:46:22 -0000
@@ -754,19 +754,62 @@
 ])
 
 AC_CHECK_FUNCS([vsnprintf snprintf])
+if test x$ac_cv_func_snprintf = xyes; then
+  AC_CACHE_CHECK([whether snprintf works], kde_cv_snprintf_ok, [
+    AC_TRY_RUN([
+#include <stdio.h>
+
+int main()
+{
+    char buf[11];
+
+    buf[10] = 'O';
+    snprintf(buf, 10, "0123456789");
+    /* extra paranoia */
+    snprintf(buf, 10, "01234%s", "56789");
+    snprintf(buf, 10, "01234%d", 56789);
+    if (buf[10] != 'O')
+	return 1;	/* buffer can overflow */
+    if (buf[9])
+	return 83;	/* buffer not null-terminated */
+    return 0;
+}],
+      [kde_cv_snprintf_ok=yes],
+      [if test x$ac_result = x83; then
+         kde_cv_snprintf_ok=mostly
+       else
+         kde_cv_snprintf_ok=no
+       fi],
+      [kde_cv_snprintf_ok=unknown]
+    )
+  ])
+  if test x$kde_cv_snprintf_ok = xno; then
+    AC_MSG_ERROR([The snprintf() implementation in your c library
+is seriously broken. Upgrade it and try again.
+Please inform security at kde.org that this happened. Don't forget to report the
+exact description of the build environment.])
+  elif test x$kde_cv_snprintf_ok != xyes; then
+    if test x$kde_cv_snprintf_ok = xunknown; then
+      AC_MSG_WARN([Cannot test whether snprintf() works (cross-compile)])
+    fi
+    AC_DEFINE(SNPRINTF_BROKEN, 1, [Define this if snprintf() does not always null-terminate])
+  fi
+fi
+
+AH_VERBATIM(_SNPRINTF,[
+
+#ifdef SNPRINTF_BROKEN
+# define snprintf snprintf_wrapper
+# define vsnprintf vsnprintf_wrapper
+#endif
 
-AH_VERBATIM(_TRU64,[
 /*
  * On HP-UX, the declaration of vsnprintf() is needed every time !
  */
 
-#if !defined(HAVE_VSNPRINTF) || defined(hpux)
-#if __STDC__
+#if !defined(HAVE_VSNPRINTF) || defined(SNPRINTF_BROKEN) || defined(hpux)
 #include <stdarg.h>
 #include <stdlib.h>
-#else
-#include <varargs.h>
-#endif
 #ifdef __cplusplus
 extern "C"
 #endif
Index: kdecore/vsnprintf.c
===================================================================
RCS file: /home/kde/kdelibs/kdecore/vsnprintf.c,v
retrieving revision 1.6
diff -u -r1.6 vsnprintf.c
--- kdecore/vsnprintf.c	19 Jan 2002 16:11:39 -0000	1.6
+++ kdecore/vsnprintf.c	9 Dec 2002 12:46:22 -0000
@@ -1,4 +1,5 @@
 #include "config.h"
+
 #ifndef HAVE_VSNPRINTF
 
 /*
@@ -34,12 +35,8 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
-#if __STDC__
 #include <stdarg.h>
 #include <stdlib.h>
-#else
-#include <varargs.h>
-#endif
 #include <setjmp.h>
 
 #ifndef roundup
@@ -104,15 +101,7 @@
 }
 
 int
-#if __STDC__
 vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
-#else
-vsnprintf(str, n, fmt, ap)
-	char *str;
-	size_t n;
-	char *fmt;
-	char *ap;
-#endif
 {
 	struct sigaction osa, nsa;
 	char *p;
@@ -140,31 +129,50 @@
 }
 
 int
-#if __STDC__
 snprintf(char *str, size_t n, char const *fmt, ...)
-#else
-snprintf(str, n, fmt, va_alist)
-	char *str;
-	size_t n;
-	char *fmt;
-	va_dcl
-#endif
 {
+	int r;
 	va_list ap;
-#if __STDC__
-	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
 
-	return (vsnprintf(str, n, fmt, ap));
+	va_start(ap, fmt);
+	r = vsnprintf(str, n, fmt, ap);
 	va_end(ap);
+	return r;
 }
 
+#elif defined(SNPRINTF_BROKEN)
+# undef snprintf
+# undef vsnprintf
 
-#endif
+int
+vsnprintf_wrapper(char *str, size_t n, char const *fmt, va_list ap)
+{
+	unsigned r;
+
+	r = vsnprintf(str, n, fmt, ap);
+	if (r >= n && n)	/* catches both r == -1 and r >= n */
+	    str[n - 1] = 0;
+	return r;
+}
+
+int
+snprintf_wrapper(char *str, size_t n, char const *fmt, ...)
+{
+	int r;
+	va_list ap;
+
+	va_start(ap, fmt);
+	r = vsnprintf_wrapper(str, n, fmt, ap);
+	va_end(ap);
+	return r;
+}
+
+#else
 
-/* ANSI C forbids en empty source file... */
+/* ANSI C forbids empty source files... */
 static void dummy_func() {
    dummy_func();
 }
+
+#endif
+


More information about the kde-core-devel mailing list