summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2011-05-04 00:19:21 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2011-05-04 00:19:21 -0700
commitc378da0b47eb8c26fc8da4d89e128ee3c73537de (patch)
tree69780b09fd68c972f69c1414d48c84cb24a075fa
parent288b08c747644d42c1636c2b469f8c34836ccd35 (diff)
downloademacs-c378da0b47eb8c26fc8da4d89e128ee3c73537de.tar.gz
Use C99's va_copy to avoid undefined behavior on x86-64 GNU/Linux.
-rw-r--r--ChangeLog4
-rw-r--r--Makefile.in2
-rw-r--r--lib/gnulib.mk29
-rw-r--r--lib/stdarg.in.h36
-rw-r--r--m4/gl-comp.m49
-rw-r--r--m4/stdarg.m478
-rw-r--r--src/ChangeLog3
-rw-r--r--src/eval.c5
8 files changed, 163 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index a9446476bc6..c1e774c2924 100644
--- 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.
diff --git a/Makefile.in b/Makefile.in
index 180f7e5be16..ba2926d2853 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
index faf89aaa0e6..1466e430a4c 100644
--- a/lib/gnulib.mk
+++ b/lib/gnulib.mk
@@ -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
index 00000000000..4469d54e4f4
--- /dev/null
+++ b/lib/stdarg.in.h
@@ -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 */
diff --git a/m4/gl-comp.m4 b/m4/gl-comp.m4
index 4338f2036b1..87d7616f8bb 100644
--- a/m4/gl-comp.m4
+++ b/m4/gl-comp.m4
@@ -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
index 00000000000..5705de9ecaa
--- /dev/null
+++ b/m4/stdarg.m4
@@ -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])
+])
diff --git a/src/ChangeLog b/src/ChangeLog
index 9fac265ae48..a1aa19e6f2e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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.
diff --git a/src/eval.c b/src/eval.c
index 90ef02ef37b..6b4182cb319 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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