]> granicus.if.org Git - sudo/commitdiff
Add check for C99 compliant (v)snprintf function.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 19 Nov 2013 17:40:25 +0000 (10:40 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 19 Nov 2013 17:40:25 +0000 (10:40 -0700)
MANIFEST
aclocal.m4
compat/snprintf.c
config.h.in
configure
configure.ac
m4/ax_func_snprintf.m4 [new file with mode: 0644]

index f8207316fcf396dd6d5c489059b60732a285cff3..c8a37f75bf96d8cde64e041a9b26e9973f458265 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -157,6 +157,7 @@ install-sh
 ltmain.sh
 m4/ax_check_compile_flag.m4
 m4/ax_check_link_flag.m4
+m4/ax_func_snprintf.m4
 m4/libtool.m4
 m4/ltoptions.m4
 m4/ltsugar.m4
index fe5f1629fbd89ed62ffb4fc02332436532ef6996..cc710d45485a6dc9428a80935c7a5a8d7705c2ea 100644 (file)
@@ -128,6 +128,7 @@ AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
 
 m4_include([m4/ax_check_compile_flag.m4])
 m4_include([m4/ax_check_link_flag.m4])
+m4_include([m4/ax_func_snprintf.m4])
 m4_include([m4/libtool.m4])
 m4_include([m4/ltoptions.m4])
 m4_include([m4/ltsugar.m4])
index 93f49ed01fff7468c44254233fa623fa1e3d4d12..7384ecfa31bc522182e7271e9917fc4819607b19 100644 (file)
@@ -41,7 +41,9 @@
 
 #include <config.h>
 
-#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_SNPRINTF) || !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF)
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_SNPRINTF) || \
+    !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF) || \
+    defined(PREFER_PORTABLE_SNPRINTF)
 
 #include <sys/types.h>
 
@@ -668,16 +670,16 @@ done:
        /* NOTREACHED */
 }
 
-#ifndef HAVE_VSNPRINTF
+#if !defined(HAVE_VSNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
 int
 vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
 {
 
        return xxxprintf(&str, n, 0, fmt, ap);
 }
-#endif /* HAVE_VSNPRINTF */
+#endif /* !HAVE_VSNPRINTF || PREFER_PORTABLE_SNPRINTF */
 
-#ifndef HAVE_SNPRINTF
+#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
 int
 snprintf(char *str, size_t n, char const *fmt, ...)
 {
@@ -689,18 +691,18 @@ snprintf(char *str, size_t n, char const *fmt, ...)
        va_end(ap);
        return ret;
 }
-#endif /* HAVE_SNPRINTF */
+#endif /* !HAVE_SNPRINTF || PREFER_PORTABLE_SNPRINTF */
 
-#ifndef HAVE_VASPRINTF
+#if !defined(HAVE_VASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
 int
 vasprintf(char **str, const char *fmt, va_list ap)
 {
 
        return xxxprintf(str, 0, 1, fmt, ap);
 }
-#endif /* HAVE_VASPRINTF */
+#endif /* !HAVE_VASPRINTF || PREFER_PORTABLE_SNPRINTF */
 
-#ifndef HAVE_ASPRINTF
+#if !defined(HAVE_ASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
 int
 asprintf(char **str, char const *fmt, ...)
 {
@@ -712,6 +714,6 @@ asprintf(char **str, char const *fmt, ...)
        va_end(ap);
        return ret;
 }
-#endif /* HAVE_ASPRINTF */
+#endif /* !HAVE_ASPRINTF || PREFER_PORTABLE_SNPRINTF */
 
-#endif /* !HAVE_VSNPRINTF || !HAVE_SNPRINTF || !HAVE_VASPRINTF || !HAVE_ASPRINTF */
+#endif /* !HAVE_VSNPRINTF || !HAVE_SNPRINTF || !HAVE_VASPRINTF || !HAVE_ASPRINTF || PREFER_PORTABLE_SNPRINTF */
index 9d42f063e0c452f37c2680007e76718f2ba0509b..4dd53988277068fcf22abf17792b8a52a3daf93c 100644 (file)
    ones. */
 #undef PC_INSULTS
 
+/* Enable replacement (v)snprintf if system (v)snprintf is broken. */
+#undef PREFER_PORTABLE_SNPRINTF
+
 /* The syslog priority sudo will use for unsuccessful attempts/errors. */
 #undef PRI_FAILURE
 
index 06cb7a6e64565602ee91c24d93fc0b9c80fc3eac..38b16153eec927b88ad6e141b2716819735126c0 100755 (executable)
--- a/configure
+++ b/configure
@@ -17851,7 +17851,7 @@ esac
 fi
 done
 
-for ac_func in snprintf vsnprintf asprintf vasprintf
+for ac_func in snprintf vsnprintf
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -17860,11 +17860,134 @@ if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working snprintf" >&5
+$as_echo_n "checking for working snprintf... " >&6; }
+if ${ac_cv_have_working_snprintf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_have_working_snprintf=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+
+int main(void)
+{
+    char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
+    char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
+    int i;
+    i = snprintf (bufs, 2, "%s", "111");
+    if (strcmp (bufs, "1")) exit (1);
+    if (i != 3) exit (1);
+    i = snprintf (bufd, 2, "%d", 111);
+    if (strcmp (bufd, "1")) exit (1);
+    if (i != 3) exit (1);
+    exit(0);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_have_working_snprintf=yes
+else
+  ac_cv_have_working_snprintf=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_working_snprintf" >&5
+$as_echo "$ac_cv_have_working_snprintf" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vsnprintf" >&5
+$as_echo_n "checking for working vsnprintf... " >&6; }
+if ${ac_cv_have_working_vsnprintf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_have_working_vsnprintf=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+#include <stdarg.h>
+
+int my_vsnprintf (char *buf, const char *tmpl, ...)
+{
+    int i;
+    va_list args;
+    va_start (args, tmpl);
+    i = vsnprintf (buf, 2, tmpl, args);
+    va_end (args);
+    return i;
+}
+
+int main(void)
+{
+    char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
+    char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
+    int i;
+    i = my_vsnprintf (bufs, "%s", "111");
+    if (strcmp (bufs, "1")) exit (1);
+    if (i != 3) exit (1);
+    i = my_vsnprintf (bufd, "%d", 111);
+    if (strcmp (bufd, "1")) exit (1);
+    if (i != 3) exit (1);
+    exit(0);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_have_working_vsnprintf=yes
 else
-  NEED_SNPRINTF=1
+  ac_cv_have_working_vsnprintf=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_working_vsnprintf" >&5
+$as_echo "$ac_cv_have_working_vsnprintf" >&6; }
+if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes"; then
+  case " $LIBOBJS " in
+  *" snprintf.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Replacing missing/broken (v)snprintf() with sudo's version." >&5
+$as_echo "$as_me: WARNING: Replacing missing/broken (v)snprintf() with sudo's version." >&2;}
+
+$as_echo "#define PREFER_PORTABLE_SNPRINTF 1" >>confdefs.h
+
+fi
+for ac_func in asprintf vasprintf
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
 fi
 done
 
+if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes"; then
+    # Don't add snprintf to LIBOBJS if it is already present.
+    if test X"$ac_cv_func_asprintf$ac_cv_func_vasprintf" != X"yesyes"; then
+       case " $LIBOBJS " in
+  *" snprintf.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+    fi
+fi
 if test X"$ac_cv_type_struct_timespec" != X"no"; then
     ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default"
 if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then :
@@ -18174,14 +18297,6 @@ _ACEOF
 
 fi
 
-if test -n "$NEED_SNPRINTF"; then
-    case " $LIBOBJS " in
-  *" snprintf.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
- ;;
-esac
-
-fi
 ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket"
 if test "x$ac_cv_func_socket" = xyes; then :
 
index c9e3a6822327211ecbbdb25b0c8361df51ff7ec2..a55e23a9d27f70c497db9457ecca4f9fb952de32 100644 (file)
@@ -2401,7 +2401,14 @@ AC_CHECK_FUNCS(mkstemps mkdtemp, [], [
     AC_CHECK_FUNCS(random lrand48, [break])
     AC_LIBOBJ(mktemp)
 ])
-AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf, , [NEED_SNPRINTF=1])
+AX_FUNC_SNPRINTF
+AC_CHECK_FUNCS(asprintf vasprintf)
+if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes"; then
+    # Don't add snprintf to LIBOBJS if it is already present.
+    if test X"$ac_cv_func_asprintf$ac_cv_func_vasprintf" != X"yesyes"; then
+       AC_LIBOBJ(snprintf)
+    fi
+fi
 if test X"$ac_cv_type_struct_timespec" != X"no"; then
     AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE(HAVE_ST_MTIM)]
        [AC_CHECK_MEMBER([struct stat.st_mtim.st__tim], AC_DEFINE(HAVE_ST__TIM))],
@@ -2466,13 +2473,6 @@ AC_INCLUDES_DEFAULT
 #include <$ac_header_dirent>
 ])
 dnl
-dnl If NEED_SNPRINTF is set, add snprintf.c to LIBOBJS
-dnl (it contains snprintf, vsnprintf, asprintf, and vasprintf)
-dnl
-if test -n "$NEED_SNPRINTF"; then
-    AC_LIBOBJ(snprintf)
-fi
-dnl
 dnl If socket(2) not in libc, check -lsocket and -linet
 dnl May need to link with *both* -lnsl and -lsocket due to unresolved symbols
 dnl
diff --git a/m4/ax_func_snprintf.m4 b/m4/ax_func_snprintf.m4
new file mode 100644 (file)
index 0000000..f0dccf0
--- /dev/null
@@ -0,0 +1,82 @@
+# ===========================================================================
+#     http://www.gnu.org/software/autoconf-archive/ax_func_snprintf.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_FUNC_SNPRINTF
+#
+# DESCRIPTION
+#
+#   Checks for a fully C99 compliant snprintf, in particular checks whether
+#   it does bounds checking and returns the correct string length; does the
+#   same check for vsnprintf. If no working snprintf or vsnprintf is found,
+#   request a replacement and warn the user about it. Note: the mentioned
+#   replacement is freely available and may be used in any project
+#   regardless of it's license.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Ruediger Kuhlmann <info@ruediger-kuhlmann.de>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 5
+
+AC_DEFUN([AX_FUNC_SNPRINTF],
+[AC_CHECK_FUNCS(snprintf vsnprintf)
+AC_MSG_CHECKING(for working snprintf)
+AC_CACHE_VAL(ac_cv_have_working_snprintf,
+[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
+
+int main(void)
+{
+    char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
+    char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
+    int i;
+    i = snprintf (bufs, 2, "%s", "111");
+    if (strcmp (bufs, "1")) exit (1);
+    if (i != 3) exit (1);
+    i = snprintf (bufd, 2, "%d", 111);
+    if (strcmp (bufd, "1")) exit (1);
+    if (i != 3) exit (1);
+    exit(0);
+}]])],[ac_cv_have_working_snprintf=yes],[ac_cv_have_working_snprintf=no],[ac_cv_have_working_snprintf=cross])])
+AC_MSG_RESULT([$ac_cv_have_working_snprintf])
+AC_MSG_CHECKING(for working vsnprintf)
+AC_CACHE_VAL(ac_cv_have_working_vsnprintf,
+[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
+#include <stdarg.h>
+
+int my_vsnprintf (char *buf, const char *tmpl, ...)
+{
+    int i;
+    va_list args;
+    va_start (args, tmpl);
+    i = vsnprintf (buf, 2, tmpl, args);
+    va_end (args);
+    return i;
+}
+
+int main(void)
+{
+    char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
+    char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
+    int i;
+    i = my_vsnprintf (bufs, "%s", "111");
+    if (strcmp (bufs, "1")) exit (1);
+    if (i != 3) exit (1);
+    i = my_vsnprintf (bufd, "%d", 111);
+    if (strcmp (bufd, "1")) exit (1);
+    if (i != 3) exit (1);
+    exit(0);
+}]])],[ac_cv_have_working_vsnprintf=yes],[ac_cv_have_working_vsnprintf=no],[ac_cv_have_working_vsnprintf=cross])])
+AC_MSG_RESULT([$ac_cv_have_working_vsnprintf])
+if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes"; then
+  AC_LIBOBJ(snprintf)
+  AC_MSG_WARN([Replacing missing/broken (v)snprintf() with sudo's version.])
+  AC_DEFINE(PREFER_PORTABLE_SNPRINTF, 1, [Enable replacement (v)snprintf if system (v)snprintf is broken.])
+fi])