Use C99's va_copy to avoid undefined behavior on x86-64 GNU/Linux.

This commit is contained in:
Paul Eggert 2011-05-04 00:19:21 -07:00
parent 288b08c747
commit c378da0b47
8 changed files with 163 additions and 3 deletions

View file

@ -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.

View 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

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

36
lib/stdarg.in.h Normal file
View file

@ -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 */

View 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

78
m4/stdarg.m4 Normal file
View file

@ -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])
])

View 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.

View 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