Use C99's va_copy to avoid undefined behavior on x86-64 GNU/Linux.
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 4 May 2011 07:19:21 +0000 (00:19 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 4 May 2011 07:19:21 +0000 (00:19 -0700)
ChangeLog
Makefile.in
lib/gnulib.mk
lib/stdarg.in.h [new file with mode: 0644]
m4/gl-comp.m4
m4/stdarg.m4 [new file with mode: 0644]
src/ChangeLog
src/eval.c

index a944647..c1e774c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2011-05-04  Paul Eggert  <eggert@cs.ucla.edu>
 
+       Use C99's va_copy to avoid undefined behavior on x86-64 GNU/Linux.
+       * Makefile.in (GNULIB_MODULES): Add stdarg, for va_copy.
+       * lib/stdarg.in.h, m4/stdarg.m4: New files, from gnulib.
+
        * Makefile.in (GNULIB_TOOL_FLAG): Add --conditional-dependencies.
        This new gnulib-tool option saves 'configure' the trouble of
        checking for strtoull when strtoumax exists.
index 180f7e5..ba2926d 100644 (file)
@@ -333,7 +333,7 @@ DOS_gnulib_comp.m4 = gl-comp.m4
 GNULIB_MODULES = \
   careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu \
   ignore-value intprops lstat mktime readlink \
-  socklen stdio strftime strtoumax symlink sys_stat
+  socklen stdarg stdio strftime strtoumax symlink sys_stat
 GNULIB_TOOL_FLAGS = \
  --conditional-dependencies --import --no-changelog --no-vc-files \
  --makefile-name=gnulib.mk
index faf89aa..1466e43 100644 (file)
@@ -9,7 +9,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --makefile-name=gnulib.mk --no-libtool --macro-prefix=gl --no-vc-files careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu ignore-value intprops lstat mktime readlink socklen stdio strftime strtoumax symlink sys_stat
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --makefile-name=gnulib.mk --no-libtool --macro-prefix=gl --no-vc-files careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu ignore-value intprops lstat mktime readlink socklen stdarg stdio strftime strtoumax symlink sys_stat
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -258,6 +258,33 @@ EXTRA_libgnu_a_SOURCES += stat.c
 
 ## end   gnulib module stat
 
+## begin gnulib module stdarg
+
+BUILT_SOURCES += $(STDARG_H)
+
+# We need the following in order to create <stdarg.h> when the system
+# doesn't have one that works with the given compiler.
+if GL_GENERATE_STDARG_H
+stdarg.h: stdarg.in.h $(top_builddir)/config.status
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
+         sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+             -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+             -e 's|@''NEXT_STDARG_H''@|$(NEXT_STDARG_H)|g' \
+             < $(srcdir)/stdarg.in.h; \
+       } > $@-t && \
+       mv $@-t $@
+else
+stdarg.h: $(top_builddir)/config.status
+       rm -f $@
+endif
+MOSTLYCLEANFILES += stdarg.h stdarg.h-t
+
+EXTRA_DIST += stdarg.in.h
+
+## end   gnulib module stdarg
+
 ## begin gnulib module stdbool
 
 BUILT_SOURCES += $(STDBOOL_H)
diff --git a/lib/stdarg.in.h b/lib/stdarg.in.h
new file mode 100644 (file)
index 0000000..4469d54
--- /dev/null
@@ -0,0 +1,36 @@
+/* Substitute for and wrapper around <stdarg.h>.
+   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _GL_STDARG_H
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+/* The include_next requires a split double-inclusion guard.  */
+#@INCLUDE_NEXT@ @NEXT_STDARG_H@
+
+#ifndef _GL_STDARG_H
+#define _GL_STDARG_H
+
+#ifndef va_copy
+# define va_copy(a,b) ((a) = (b))
+#endif
+
+#endif /* _GL_STDARG_H */
+#endif /* _GL_STDARG_H */
index 4338f20..87d7616 100644 (file)
@@ -51,6 +51,12 @@ AC_DEFUN([gl_EARLY],
   # Code from module socklen:
   # Code from module ssize_t:
   # Code from module stat:
+  # Code from module stdarg:
+  dnl Some compilers (e.g., AIX 5.3 cc) need to be in c99 mode
+  dnl for the builtin va_copy to work.  With Autoconf 2.60 or later,
+  dnl AC_PROG_CC_STDC arranges for this.  With older Autoconf AC_PROG_CC_STDC
+  dnl shouldn't hurt, though installers are on their own to set c99 mode.
+  AC_REQUIRE([AC_PROG_CC_STDC])
   # Code from module stdbool:
   # Code from module stddef:
   # Code from module stdint:
@@ -104,6 +110,7 @@ gl_FUNC_READLINK
 gl_UNISTD_MODULE_INDICATOR([readlink])
 gl_TYPE_SOCKLEN_T
 gt_TYPE_SSIZE_T
+gl_STDARG_H
 AM_STDBOOL_H
 gl_STDDEF_H
 gl_STDINT_H
@@ -358,6 +365,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/mktime.c
   lib/readlink.c
   lib/stat.c
+  lib/stdarg.in.h
   lib/stdbool.in.h
   lib/stddef.in.h
   lib/stdint.in.h
@@ -395,6 +403,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/ssize_t.m4
   m4/st_dm_mode.m4
   m4/stat.m4
+  m4/stdarg.m4
   m4/stdbool.m4
   m4/stddef_h.m4
   m4/stdint.m4
diff --git a/m4/stdarg.m4 b/m4/stdarg.m4
new file mode 100644 (file)
index 0000000..5705de9
--- /dev/null
@@ -0,0 +1,78 @@
+# stdarg.m4 serial 6
+dnl Copyright (C) 2006, 2008-2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Provide a working va_copy in combination with <stdarg.h>.
+
+AC_DEFUN([gl_STDARG_H],
+[
+  STDARG_H=''
+  NEXT_STDARG_H='<stdarg.h>'
+  AC_MSG_CHECKING([for va_copy])
+  AC_CACHE_VAL([gl_cv_func_va_copy], [
+    AC_COMPILE_IFELSE(
+      [AC_LANG_PROGRAM(
+         [[#include <stdarg.h>]],
+         [[
+#ifndef va_copy
+void (*func) (va_list, va_list) = va_copy;
+#endif
+         ]])],
+      [gl_cv_func_va_copy=yes],
+      [gl_cv_func_va_copy=no])])
+  AC_MSG_RESULT([$gl_cv_func_va_copy])
+  if test $gl_cv_func_va_copy = no; then
+    dnl Provide a substitute.
+    dnl Usually a simple definition in <config.h> is enough. Not so on AIX 5
+    dnl with some versions of the /usr/vac/bin/cc compiler. It has an <stdarg.h>
+    dnl which does '#undef va_copy', leading to a missing va_copy symbol. For
+    dnl this platform, we use an <stdarg.h> substitute. But we cannot use this
+    dnl approach on other platforms, because <stdarg.h> often defines only
+    dnl preprocessor macros and gl_ABSOLUTE_HEADER, gl_CHECK_NEXT_HEADERS do
+    dnl not work in this situation.
+    AC_EGREP_CPP([vaccine],
+      [#if defined _AIX && !defined __GNUC__
+        AIX vaccine
+       #endif
+      ], [gl_aixcc=yes], [gl_aixcc=no])
+    if test $gl_aixcc = yes; then
+      dnl Provide a substitute <stdarg.h> file.
+      STDARG_H=stdarg.h
+      gl_NEXT_HEADERS([stdarg.h])
+      dnl Fallback for the case when <stdarg.h> contains only macro definitions.
+      if test "$gl_cv_next_stdarg_h" = '""'; then
+        gl_cv_next_stdarg_h='"///usr/include/stdarg.h"'
+        NEXT_STDARG_H="$gl_cv_next_stdarg_h"
+      fi
+    else
+      dnl Provide a substitute in <config.h>, either __va_copy or as a simple
+      dnl assignment.
+      gl_CACHE_VAL_SILENT([gl_cv_func___va_copy], [
+        AC_COMPILE_IFELSE(
+          [AC_LANG_PROGRAM(
+             [[#include <stdarg.h>]],
+             [[
+#ifndef __va_copy
+error, bail out
+#endif
+             ]])],
+          [gl_cv_func___va_copy=yes],
+          [gl_cv_func___va_copy=no])])
+      if test $gl_cv_func___va_copy = yes; then
+        AC_DEFINE([va_copy], [__va_copy],
+          [Define as a macro for copying va_list variables.])
+      else
+        AH_VERBATIM([gl_VA_COPY], [/* A replacement for va_copy, if needed.  */
+#define gl_va_copy(a,b) ((a) = (b))])
+        AC_DEFINE([va_copy], [gl_va_copy],
+          [Define as a macro for copying va_list variables.])
+      fi
+    fi
+  fi
+  AC_SUBST([STDARG_H])
+  AM_CONDITIONAL([GL_GENERATE_STDARG_H], [test -n "$STDARG_H"])
+  AC_SUBST([NEXT_STDARG_H])
+])
index 9fac265..a1aa19e 100644 (file)
@@ -1,5 +1,8 @@
 2011-05-04  Paul Eggert  <eggert@cs.ucla.edu>
 
+       Use C99's va_copy to avoid undefined behavior on x86-64 GNU/Linux.
+       * eval.c (verror): doprnt a copy of ap, not the original.  (Bug#8545)
+
        * eval.c (verror): OK to create a string of up to MOST_POSITIVE_FIXNUM
        bytes.
 
index 90ef02e..6b4182c 100644 (file)
@@ -2002,7 +2002,10 @@ verror (const char *m, va_list ap)
 
   while (1)
     {
-      used = doprnt (buffer, size, m, m + mlen, ap);
+      va_list ap_copy;
+      va_copy (ap_copy, ap);
+      used = doprnt (buffer, size, m, m + mlen, ap_copy);
+      va_end (ap_copy);
 
       /* Note: the -1 below is because `doprnt' returns the number of bytes
         excluding the terminating null byte, and it always terminates with a