On Thu, Nov 12, 2009 at 02:37:58PM -0500, Chet Ramey wrote:
> I try to write to the current (well, ten-year-old) standards. The
> replacement in lib/sh/snprintf.c behaves as C99 specifies; you might try
> using it by #undefing HAVE_VSNPRINTF and HAVE_SNPRINTF in config.h.
Ah, wonderful. I wasted a bit of time looking for a replacement
vsnprintf function on the Internet, but you already have one. ;-)
That worked. (Note to self: not #define HAVE_FOO 0. It has to be #undef.)
Here's a patch that tries to do this automatically. I wanted to make
it simpler, preferably doing something like "AC_UNDEFINE(HAVE_FOO)" if it
fails, but apparently that's not possible. Hence, the ugly SNPRINTF_BROKEN
definition and the multiple touched files.
One potential issue with this patch: I noticed that there's an existing
autoconf macro for systems that require a special _KERNEL definition to
use the RLIMIT_* constants in setrlimit(). This patch doesn't know
about that, unfortunately, and I wasn't sure how to do that properly in
autoconf.
Tested & worked on HP-UX 10.20.
This patch detects the broken (v)snprintf functions on HP-UX and uses
the replacement function provided in the bash source. Normally this
function is only used if no (v)snprintf is discovered at all.
To use:
.../bash-4.0$ patch -p1 < ../bash-4.0-snprintf.diff
.../bash-4.0$ autoconf
.../bash-4.0$ ./configure [options]
.../bash-4.0$ make
--- bash-4.0/configure.in Fri Feb 6 12:03:44 2009
+++ bash-4.0-gw/configure.in Thu Nov 12 16:38:31 2009
@@ -725,7 +725,64 @@
setenv setlinebuf setlocale setvbuf siginterrupt strchr \
sysconf tcgetattr times ttyname tzset unsetenv)
-AC_CHECK_FUNCS(vsnprintf snprintf vasprintf asprintf)
+AC_CHECK_FUNCS(snprintf vsnprintf)
+dnl HP-UX 10.20 and 11.11 (at least) have present-but-broken (v)snprintf.
+dnl Among other undesirable behavior, it segfaults when the first argument
+dnl is null and the second is 0. C99 says this is allowed. This test is
+dnl not sufficient to find ALL the broken behaviors; just the segfault.
+if test "x$ac_cv_func_snprintf" = "xyes"; then
+ AC_MSG_CHECKING([for working snprintf])
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <sys/resource.h>
+main() {
+ struct rlimit r;
+ r.rlim_cur = r.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &r);
+ snprintf(NULL, 0, "%s", "");
+ return 0;
+}
+ ]])],
+ [AC_MSG_RESULT(yes)],
+ [
+ AC_MSG_RESULT(no)
+ AC_DEFINE(SNPRINTF_BROKEN, 1, [Define if snprintf is broken])
+ ],
+ [ AC_MSG_WARN([cross compiling: Assuming working snprintf]) ]
+ )
+fi
+if test "x$ac_cv_func_vsnprintf" = "xyes"; then
+ AC_MSG_CHECKING([for working vsnprintf])
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/resource.h>
+void foo(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
+}
+main() {
+ struct rlimit r;
+ r.rlim_cur = r.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &r);
+ foo("%s", "");
+ return 0;
+}
+ ]])],
+ [AC_MSG_RESULT(yes)],
+ [
+ AC_MSG_RESULT(no)
+ AC_DEFINE(VSNPRINTF_BROKEN, 1, [Define if vsnprintf is broken])
+ ],
+ [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf]) ]
+ )
+fi
+
+AC_CHECK_FUNCS(vasprintf asprintf)
AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
AC_CHECK_FUNCS(getpwent getpwnam getpwuid)
AC_REPLACE_FUNCS(getcwd memset strcasecmp strerror strftime strnlen strpbrk
strstr)
--- bash-4.0/config.h.in Sun Feb 1 17:07:23 2009
+++ bash-4.0-gw/config.h.in Thu Nov 12 16:19:40 2009
@@ -1019,6 +1031,10 @@
#undef DUP2_BROKEN
#undef GETCWD_BROKEN
+
+#undef SNPRINTF_BROKEN
+
+#undef VSNPRINTF_BROKEN
/* Additional defines for configuring lib/intl, maintained by
autoscan/autoheader */
--- bash-4.0/builtins/printf.def Sun Jan 18 18:37:07 2009
+++ bash-4.0-gw/builtins/printf.def Thu Nov 12 16:27:36 2009
@@ -170,7 +170,7 @@
extern int asprintf __P((char **, const char *, ...))
__attribute__((__format__ (printf, 2, 3)));
#endif
-#ifndef HAVE_VSNPRINTF
+#if !defined (HAVE_VSNPRINTF) || defined (VSNPRINTF_BROKEN)
extern int vsnprintf __P((char *, size_t, const char *, ...))
__attribute__((__format__ (printf, 3, 4)));
#endif
--- bash-4.0/lib/sh/snprintf.c Tue Aug 12 12:02:14 2008
+++ bash-4.0-gw/lib/sh/snprintf.c Thu Nov 12 16:34:50 2009
@@ -82,7 +82,7 @@
#define intmax_t long
#endif
-#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF)
+#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF) || defined
(SNPRINTF_BROKEN)
#include <bashtypes.h>
@@ -1640,7 +1640,7 @@
}
#endif /* FLOATING_POINT */
-#ifndef HAVE_SNPRINTF
+#if !defined (HAVE_SNPRINTF) || defined (SNPRINTF_BROKEN)
int
#if defined (__STDC__)