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__)

Reply via email to