From 3923d6eba0c5071b1c73a4d3e02f6ae0b6b1c365 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Tue, 7 Sep 2010 20:54:44 +0100 Subject: [PATCH] Let configure check for the varargs/_Bool interaction According to the C standard, passing _Bool via varargs is undefined behaviour. This lets autoconf check to see whether it actually works, and casts to int in the relevant location if it doesn't. (Recent gcc will compile an attempt to access a boolean via varargs into an illegal instruction.) --- configure.ac | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/cesspool.c | 4 ++++ src/feh2.c | 5 +++++ 3 files changed, 54 insertions(+) diff --git a/configure.ac b/configure.ac index 948e331..4f2cf61 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,51 @@ AC_TYPE_SIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T +# Some compilers (correctly according to the standard, but dubiously for +# actual use in code) dislike mixing _Bool and varargs. +if test "x$ac_cv_type__Bool" == "xyes" +then +AC_MSG_CHECKING([[whether booleans can be passed via varargs]]) +AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +#ifdef HAVE_STDARG_H +#include +void test(int x, ...) +#else +#include +void test(va_alist) va_dcl +#endif +{ + int y,z; + _Bool b; + va_list ap; +#ifdef HAVE_STDARG_H + va_start(ap, x); + y = x; +#else + va_start(ap); + y = va_arg(ap, int); +#endif + b = va_arg(ap, _Bool); + z = va_arg(ap, int); + if(b && x != z) exit(2); + if(!b && x == z) exit(3); +} +]],[[ +_Bool match = (_Bool)1; +_Bool nomatch = (_Bool) 0; +test(12345,match,12345); +test(23456,nomatch,1234); +exit(0); +]])],[AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no) +AC_DEFINE([BOOL_VARARGS_BROKEN],[],dnl +[Define if _Bool works but cannot be passed via varargs.]) +],[AC_MSG_RESULT([[unknown in a cross-compile, assuming no]]) +AC_DEFINE([BOOL_VARARGS_BROKEN],[],dnl +[Define if _Bool works but cannot be passed via varargs.]) +]) +fi + AC_MSG_CHECKING([[whether yyrestart() is needed]]) # Write a lex program that will cause an error if yyrestart exists. echo '%% diff --git a/src/cesspool.c b/src/cesspool.c index e1129b3..eb55b1f 100644 --- a/src/cesspool.c +++ b/src/cesspool.c @@ -632,7 +632,11 @@ void ick_resize(va_alist) va_dcl type = va_arg(ap, unsigned int); #endif a = va_arg(ap, ick_array*); +#ifdef BOOL_VARARGS_BROKEN + forget = (bool)va_arg(ap, int); +#else forget = va_arg(ap, bool); +#endif /* AIS: a->dims is no longer initialised. So initialise it here if it isn't already initialised, with an annotation to explain that diff --git a/src/feh2.c b/src/feh2.c index 99b4be5..3eb7148 100644 --- a/src/feh2.c +++ b/src/feh2.c @@ -2099,8 +2099,13 @@ void emit(tuple *tn, FILE *fp) dim++; (void) fprintf(fp, "\t""ick_resize("); prvar(np->lval, fp, 1); +#ifdef BOOL_VARARGS_BROKEN + (void) fprintf(fp, ", (int)%s[%lu]", nameof(np->lval->opcode, forgetbits), + np->lval->constant); +#else (void) fprintf(fp, ", %s[%lu]", nameof(np->lval->opcode, forgetbits), np->lval->constant); +#endif (void) fprintf(fp, ", %d", dim); for (sp = np->rval; sp; sp = sp->rval) { (void) fprintf(fp, ", (size_t)"); -- 2.43.0