summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2012-08-01 14:34:03 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2012-08-01 14:34:03 +0000
commitcb9434bf5db409773dd66372c52f344b8dc21d76 (patch)
tree514ef0229d1739b6cf0e41dd1f611d05dc5c74a1
parent17a2aef544bf6e90a7ec4915676ac5e433d81546 (diff)
kpathsea: Make sure snprintf() is not badly broken
if necessary, declare (v)snprintf wrapper functions git-svn-id: svn://tug.org/texlive/trunk@27271 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Build/source/texk/kpathsea/ChangeLog8
-rw-r--r--Build/source/texk/kpathsea/c-auto.in3
-rw-r--r--Build/source/texk/kpathsea/config.h69
-rwxr-xr-xBuild/source/texk/kpathsea/configure116
-rw-r--r--Build/source/texk/kpathsea/configure.ac49
-rw-r--r--Build/source/texk/kpathsea/progname.c7
6 files changed, 248 insertions, 4 deletions
diff --git a/Build/source/texk/kpathsea/ChangeLog b/Build/source/texk/kpathsea/ChangeLog
index ab35720f3ec..19cc2cb9631 100644
--- a/Build/source/texk/kpathsea/ChangeLog
+++ b/Build/source/texk/kpathsea/ChangeLog
@@ -1,3 +1,11 @@
+2012-08-01 Peter Breitenlohner <peb@mppmu.mpg.de>
+
+ * configure.ac: Bail out for a badly broken snprintf()
+ (hopefully this will not happen).
+ Check if we need (v)snprintf wrapper functions.
+ * config.h: If needed, declare (v)snprintf wrapper functions.
+ * progname.c (kpathsea_set_program_name): Check snprintf sanity.
+
2012-07-25 Peter Breitenlohner <peb@mppmu.mpg.de>
* configure.ac: Add AC_CHECK_SIZEOF([long]).
diff --git a/Build/source/texk/kpathsea/c-auto.in b/Build/source/texk/kpathsea/c-auto.in
index d4fcb84ea3c..4c585126be0 100644
--- a/Build/source/texk/kpathsea/c-auto.in
+++ b/Build/source/texk/kpathsea/c-auto.in
@@ -219,6 +219,9 @@
/* Version number of package */
#undef VERSION
+/* Define to 1 if we need (v)snprintf wrapper functions. */
+#undef WRAP_SNPRINTF
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/Build/source/texk/kpathsea/config.h b/Build/source/texk/kpathsea/config.h
index eef952d7113..49f1b41b443 100644
--- a/Build/source/texk/kpathsea/config.h
+++ b/Build/source/texk/kpathsea/config.h
@@ -103,6 +103,75 @@
#endif
#endif
+#if defined(WIN32) || defined(WRAP_SNPRINTF)
+/* All Unix systems known to us have snprintf() and vsnprintf(),
+ while all known Windows systems have _snprintf() and _vsnprintf().
+
+ Consider a call
+ RET = snprintf(BUF, SIZE, FMT, ...)
+ and let LEN be the number that would be written to BUF if SIZE were
+ sufficiently large (not counting the trailing null byte).
+
+ C99 requires that snprintf
+ (A) modifies at most the first SIZE bytes of BUF,
+ (B) writes a trailing null byte except when SIZE=0, and
+ (C) always returns LEN.
+
+ All known implementations (except some ancient buggy ones, e.g., for
+ 64-bit Solaris 7 from Oct. 1998) satisfy (A). As long as LEN<SIZE
+ they all write a trailing null byte and return LEN.
+
+ Condition (C) is, however, violated for LEN>=SIZE by some older
+ implementations (SUSv2, glibc <= 2.0.6, etc.) and for Windows even
+ (B) is violated..
+
+ TeX Live does not require the full C99 semantics, but will need that
+ (1) there is always a trailing null byte, and
+ (2) for LEN>=SIZE the return value is either >=SIZE or <0, i.e.,
+ (unsigned)RET >= (unsigned)SIZE.
+
+ A violation of (2) is detected by configure (except when cross
+ compiling) and by a runtime check in the initialization routine
+ kpathsea_set_program_name.
+
+ A violation of (1) is handled here through static inline wrapper
+ functions. */
+
+#include <stdarg.h>
+
+#undef snprintf
+#undef vsnprintf
+
+static inline int
+kpse_vsnprintf (char *str, size_t size, const char *format, va_list ap)
+{
+#ifdef WIN32
+ int ret = _vsnprintf (str, size, format, ap);
+#else
+ int ret = vsnprintf (str, size, format, ap);
+#endif
+ if (size > 0 && (unsigned)ret >= (unsigned)size)
+ str [size - 1] = '\0';
+ return ret;
+}
+
+static inline int
+kpse_snprintf (char *str, size_t size, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start (ap, format);
+ ret = kpse_vsnprintf (str, size, format, ap);
+ va_end (ap);
+ return ret;
+}
+
+#define snprintf kpse_snprintf
+#define vsnprintf kpse_vsnprintf
+
+#endif /* WIN32 || WRAP_SNPRINTF */
+
/* Transform filename characters for use in hash tables. */
#if defined(MONOCASE_FILENAMES)
#if defined(WIN32) && !defined(__i386_pc_gnu__)
diff --git a/Build/source/texk/kpathsea/configure b/Build/source/texk/kpathsea/configure
index 8641402a3ba..0e2137d3993 100755
--- a/Build/source/texk/kpathsea/configure
+++ b/Build/source/texk/kpathsea/configure
@@ -778,6 +778,7 @@ enable_mkocp_default
enable_mkofm_default
enable_mktexfmt_default
enable_mktextex_default
+with_snprintf_wrapper
'
ac_precious_vars='build_alias
host_alias
@@ -1440,6 +1441,8 @@ Optional Packages:
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-sysroot=DIR Search for dependent libraries within DIR
(or the compiler's sysroot if not specified).
+ --with-snprintf-wrapper use (v)snprintf wrapper functions [automatic for
+ native compilation or Windows]
Some influential environment variables:
CC C compiler command
@@ -13298,7 +13301,7 @@ fi
-if test $ac_cv_func_getcwd = yes; then
+if test "x$ac_cv_func_getcwd" = xyes; then
# We only need to run this if we have getcwd.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getcwd uses fork or vfork" >&5
$as_echo_n "checking whether getcwd uses fork or vfork... " >&6; }
@@ -13334,7 +13337,7 @@ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $kb_cv_func_getcwd_forks" >&5
$as_echo "$kb_cv_func_getcwd_forks" >&6; }
-if test $kb_cv_func_getcwd_forks = yes; then
+if test "x$kb_cv_func_getcwd_forks" = xyes; then
$as_echo "#define GETCWD_FORKS 1" >>confdefs.h
@@ -13407,6 +13410,115 @@ fi
LT_OBJDIR="$lt_cv_objdir"
+# Checking snprintf and vsnprintf
+
+# Check whether --with-snprintf-wrapper was given.
+if test "${with_snprintf_wrapper+set}" = set; then :
+ withval=$with_snprintf_wrapper; kpse_cv_wrap_snprintf=$withval
+else
+ test "x$kpse_cv_have_win32" != xno && kpse_cv_wrap_snprintf=yes
+fi
+if test "x$kpse_cv_have_win32" = xno; then
+ snfunc=snprintf vsnfunc=vsnprintf
+else
+ snfunc=_snprintf vsnfunc=_vsnprintf
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $snfunc and $vsnfunc" >&5
+$as_echo_n "checking for $snfunc and $vsnfunc... " >&6; }
+if ${kpse_cv_have_snfuncs+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+ char buf[16];
+ va_list ap;
+int
+main ()
+{
+$snfunc (buf, 16, "%s", "abc");
+ $vsnfunc (buf, 16, "%s", ap);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ kpse_cv_have_snfuncs=yes
+else
+ kpse_cv_have_snfuncs=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $kpse_cv_have_snfuncs" >&5
+$as_echo "$kpse_cv_have_snfuncs" >&6; }
+if test "x$kpse_cv_have_snfuncs" != xyes; then
+ as_fn_error $? "Sorry, you need $snfunc and $vsnfunc." "$LINENO" 5
+fi
+if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+char buf[4] = "abc";
+int
+main ()
+{
+if ($snfunc (buf, 1, "%s", "x") == 0 || buf[1] != 'b')
+ return 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ as_fn_error $? "Sorry, your $snfunc is badly broken." "$LINENO" 5
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need (v)snprintf wrapper functions" >&5
+$as_echo_n "checking if we need (v)snprintf wrapper functions... " >&6; }
+if ${kpse_cv_wrap_snprintf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ kpse_cv_wrap_snprintf=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+char buf[4] = "abc";
+int
+main ()
+{
+$snfunc (buf, 3, "xyz");
+ if (buf[2] != 0) return 1;
+ $snfunc (buf, 2, "xyz");
+ if (buf[1] != 0) return 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ kpse_cv_wrap_snprintf=no
+else
+ kpse_cv_wrap_snprintf=yes
+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: $kpse_cv_wrap_snprintf" >&5
+$as_echo "$kpse_cv_wrap_snprintf" >&6; }
+if test "x$kpse_cv_wrap_snprintf" = xyes; then
+
+$as_echo "#define WRAP_SNPRINTF 1" >>confdefs.h
+
+fi
+
ac_config_headers="$ac_config_headers c-auto.h:c-auto.in"
diff --git a/Build/source/texk/kpathsea/configure.ac b/Build/source/texk/kpathsea/configure.ac
index 3f305c6f356..aa7f373253b 100644
--- a/Build/source/texk/kpathsea/configure.ac
+++ b/Build/source/texk/kpathsea/configure.ac
@@ -40,7 +40,7 @@ dnl Replacement functions that may be required on ancient broken system.
AC_CHECK_DECLS([putenv, strstr])
AC_REPLACE_FUNCS([putenv strcasecmp strtol strstr])
-if test $ac_cv_func_getcwd = yes; then
+if test "x$ac_cv_func_getcwd" = xyes; then
# We only need to run this if we have getcwd.
AC_CACHE_CHECK([whether getcwd uses fork or vfork],
[kb_cv_func_getcwd_forks],
@@ -52,7 +52,7 @@ AC_CACHE_CHECK([whether getcwd uses fork or vfork],
[kb_cv_func_getcwd_forks=no],
[kb_cv_func_getcwd_forks=yes],
[kb_cv_func_getcwd_forks=no])])
-if test $kb_cv_func_getcwd_forks = yes; then
+if test "x$kb_cv_func_getcwd_forks" = xyes; then
AC_DEFINE([GETCWD_FORKS], 1,
[Define to 1 if getcwd is implemented using fork or vfork.
Let me know if you have to add this by hand because configure
@@ -66,6 +66,51 @@ AM_CONDITIONAL([MINGW32], [test "x$kpse_cv_have_win32" = xmingw32])
AC_SUBST([LT_OBJDIR], ["$lt_cv_objdir"])
+# Checking snprintf and vsnprintf
+AC_ARG_WITH([snprintf-wrapper],
+ AS_HELP_STRING([--with-snprintf-wrapper],
+ [use (v)snprintf wrapper functions @<:@automatic
+ for native compilation or Windows@:>@]),
+ [kpse_cv_wrap_snprintf=$withval],
+ [test "x$kpse_cv_have_win32" != xno && kpse_cv_wrap_snprintf=yes])[]dnl
+if test "x$kpse_cv_have_win32" = xno; then
+ snfunc=snprintf vsnfunc=vsnprintf
+else
+ snfunc=_snprintf vsnfunc=_vsnprintf
+fi
+AC_CACHE_CHECK([for $snfunc and $vsnfunc],
+ [kpse_cv_have_snfuncs],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
+ char buf[16];
+ va_list ap;]],
+ [[$snfunc (buf, 16, "%s", "abc");
+ $vsnfunc (buf, 16, "%s", ap);]])],
+ [kpse_cv_have_snfuncs=yes],
+ [kpse_cv_have_snfuncs=no])])
+if test "x$kpse_cv_have_snfuncs" != xyes; then
+ AC_MSG_ERROR([Sorry, you need $snfunc and $vsnfunc.])
+fi
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[char buf[4] = "abc";]],
+ [[if ($snfunc (buf, 1, "%s", "x") == 0 || buf[1] != 'b')
+ return 1;]])],
+ [],
+ [AC_MSG_ERROR([Sorry, your $snfunc is badly broken.])],
+ [:])
+AC_CACHE_CHECK([if we need (v)snprintf wrapper functions],
+ [kpse_cv_wrap_snprintf],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([[char buf[4] = "abc";]],
+ [[$snfunc (buf, 3, "xyz");
+ if (buf[2] != 0) return 1;
+ $snfunc (buf, 2, "xyz");
+ if (buf[1] != 0) return 1;]])],
+ [kpse_cv_wrap_snprintf=no],
+ [kpse_cv_wrap_snprintf=yes],
+ [kpse_cv_wrap_snprintf=no])])
+if test "x$kpse_cv_wrap_snprintf" = xyes; then
+ AC_DEFINE([WRAP_SNPRINTF], 1,
+ [Define to 1 if we need (v)snprintf wrapper functions.])
+fi
+
dnl Write output here, instead of putting a zillion -D's on the command line.
AC_CONFIG_HEADERS([c-auto.h:c-auto.in],
[sed -e 's/^#define PACKAGE/#define KPSE_PACKAGE/' \
diff --git a/Build/source/texk/kpathsea/progname.c b/Build/source/texk/kpathsea/progname.c
index ee5cfaff659..0bb403b0ae5 100644
--- a/Build/source/texk/kpathsea/progname.c
+++ b/Build/source/texk/kpathsea/progname.c
@@ -696,6 +696,13 @@ kpathsea_set_program_name (kpathsea kpse, const_string argv0,
}
}
+ /* Runtime check that snprintf always writes a trailing NUL byte. */
+ {
+ char buf[4] = "old";
+ assert (snprintf (buf, 2, "a") == 1 && buf[1] == '\0');
+ assert ((unsigned)snprintf (buf, 2, "ab") >= 2 && buf[1] == '\0');
+ assert ((unsigned)snprintf (buf, 2, "abc") >= 2 && buf[1] == '\0');
+ }
/* Some of the utility routines (like atou() and xfopen()) will use
FATAL and variations thereof (see lib.h) if there is a problem.