diff options
-rw-r--r-- | src/configure.in | 27 | ||||
-rw-r--r-- | src/include/k5-platform.h | 95 | ||||
-rw-r--r-- | src/lib/krb5/keytab/t_keytab.c | 12 | ||||
-rw-r--r-- | src/util/support/errors.c | 18 |
4 files changed, 138 insertions, 14 deletions
diff --git a/src/configure.in b/src/configure.in index 0240e8cbcc..947be9be1f 100644 --- a/src/configure.in +++ b/src/configure.in @@ -14,6 +14,33 @@ dnl dnl AC_REQUIRE_CPP dnl +AC_CACHE_CHECK(if va_copy is available, krb5_cv_va_copy, +[AC_COMPILE_IFELSE([ +#include <stdarg.h> +void f(va_list ap) { + va_list ap2; + va_copy(ap2, ap); + va_end(ap2); +}], krb5_cv_va_copy=yes, krb5_cv_va_copy=no)]) +if test "$krb5_cv_va_copy" = yes; then + AC_DEFINE(HAS_VA_COPY,1,[Define if va_copy macro or function is available.]) +fi +dnl +dnl Note that this isn't checking if the copied value *works*, just +dnl whether the C language constraints permit the copying. If +dnl va_list is defined as an array type, it can't be assigned. +AC_CACHE_CHECK(if va_list objects can be copied by assignment, + krb5_cv_va_simple_copy, +[AC_COMPILE_IFELSE([ +#include <stdarg.h> +void f(va_list va2) { + va_list va1; + va1 = va2; +}], krb5_cv_va_simple_copy=yes, krb5_cv_va_simple_copy=no)]) +if test "$krb5_cv_va_simple_copy" = yes; then + AC_DEFINE(CAN_COPY_VA_LIST,1,[Define if va_list objects can be simply copied by assignment.]) +fi +dnl dnl The following lines are so that configure --help gives some global dnl configuration options. dnl diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h index 757b122b3d..6cf4465066 100644 --- a/src/include/k5-platform.h +++ b/src/include/k5-platform.h @@ -1,7 +1,7 @@ /* * k5-platform.h * - * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology. + * Copyright 2003, 2004, 2005, 2007 Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -33,14 +33,19 @@ * + SIZE_MAX * + shared library init/fini hooks * + consistent getpwnam/getpwuid interfaces + * + va_copy fudged if not provided + * + [v]asprintf */ #ifndef K5_PLATFORM_H #define K5_PLATFORM_H #include "autoconf.h" -/* for memcpy */ #include <string.h> +#include <stdarg.h> +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> /* Initialization and finalization function support for libraries. @@ -403,7 +408,6 @@ typedef struct { int error; unsigned char did_run; } k5_init_t; # define UINT64_TYPE unsigned long long #endif -#include <limits.h> #ifndef SIZE_MAX # define SIZE_MAX ((size_t)((size_t)0 - 1)) #endif @@ -743,5 +747,90 @@ load_64_n (const unsigned char *p) (*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0) #endif +/* Since the original ANSI C spec left it undefined whether or + how you could copy around a va_list, C 99 added va_copy. + For old implementations, let's do our best to fake it. + + XXX Doesn't yet handle implementations with __va_copy (early draft) + or GCC's __builtin_va_copy. */ +#if defined(HAS_VA_COPY) || defined(va_copy) +/* Do nothing. */ +#elif defined(CAN_COPY_VA_LIST) +#define va_copy(dest, src) ((dest) = (src)) +#else +/* Assume array type, but still simply copyable. + + There is, theoretically, the possibility that va_start will + allocate some storage pointed to by the va_list, and in that case + we'll just lose. If anyone cares, we could try to devise a test + for that case. */ +#define va_copy(dest, src) memcmp(dest, src, sizeof(va_list)) +#endif + +/* Provide [v]asprintf interfaces. */ +#ifndef HAVE_VSNPRINTF +#error We need an implementation of vsnprintf. +#endif +#ifndef HAVE_VASPRINTF +#define vasprintf k5_vasprintf +/* On error: BSD: Set *ret to NULL. GNU: *ret is undefined. + + Since we want to be able to use the GNU version directly, we need + provide only the weaker guarantee in this version. */ +static inline int +vasprintf(char **ret, const char *format, va_list ap) +{ + va_list ap2; + char *str = NULL, *nstr; + int len = 80, len2; + + while (1) { + if (len < 0 || (size_t) len != len) { + free(str); + return -1; + } + nstr = realloc(str, (size_t) len); + if (nstr == NULL) { + free(str); + return -1; + } + str = nstr; + va_copy(ap2, ap); + len2 = vsnprintf(str, (size_t) len, format, ap2); + va_end(ap2); + if (len2 >= 0 && len2 < len) { + if (len2 < len-1) { + /* In a lot of cases, 80 will be quite a lot more than + we need. */ + nstr = realloc(str, (size_t) len2+1); + if (nstr) + str = nstr; + } + *ret = str; + return len2; + } + /* ISO C vsnprintf returns the needed length. Some old + vsnprintf implementations return -1 on truncation. */ + if (len2 >= len) + len = len2 + 1; + else + len *= 2; + } +} +/* Assume HAVE_ASPRINTF iff HAVE_VASPRINTF. */ +#define asprintf k5_asprintf +static inline int +k5_asprintf(char **ret, const char *format, ...) +{ + va_list ap; + int n; + + va_start(ap, format); + n = vasprintf(ret, format, ap); + va_end(ap); + return n; +} +#endif + #endif /* K5_PLATFORM_H */ diff --git a/src/lib/krb5/keytab/t_keytab.c b/src/lib/krb5/keytab/t_keytab.c index d16184e25d..08610abac5 100644 --- a/src/lib/krb5/keytab/t_keytab.c +++ b/src/lib/krb5/keytab/t_keytab.c @@ -370,10 +370,16 @@ static void kt_test(krb5_context context, const char *name) static void do_test(krb5_context context, const char *prefix, krb5_boolean delete) { - char name[300], filename[300]; + char *name, *filename; - sprintf(filename, "/tmp/kttest.%ld", (long) getpid()); - sprintf(name, "%s%s", prefix, filename); + if (asprintf(&filename, "/tmp/kttest.%ld", (long) getpid()) < 0) { + perror("asprintf"); + exit(1); + } + if (asprintf(&name, "%s%s", prefix, filename) < 0) { + perror("asprintf"); + exit(1); + } printf("Starting test on %s\n", name); kt_test(context, name); printf("Test on %s passed\n", name); diff --git a/src/util/support/errors.c b/src/util/support/errors.c index 56581218a2..e2101a2a9f 100644 --- a/src/util/support/errors.c +++ b/src/util/support/errors.c @@ -50,22 +50,24 @@ krb5int_vset_error (struct errinfo *ep, long code, const char *fmt, va_list args) { char *p; + char *str = NULL; + va_list args2; if (ep->msg && ep->msg != ep->scratch_buf) { free (ep->msg); ep->msg = NULL; } ep->code = code; -#ifdef HAVE_VASPRINTF - { - char *str = NULL; - if (vasprintf(&str, fmt, args) >= 0 && str != NULL) { - ep->msg = str; - return; - } + va_copy(args2, args); + if (vasprintf(&str, fmt, args2) >= 0 && str != NULL) { + va_end(args2); + ep->msg = str; + return; } -#endif + va_end(args2); + /* Allocation failure? */ vsnprintf(ep->scratch_buf, sizeof(ep->scratch_buf), fmt, args); + /* Try again, just in case. */ p = strdup(ep->scratch_buf); ep->msg = p ? p : ep->scratch_buf; } |