summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/configure.in27
-rw-r--r--src/include/k5-platform.h95
-rw-r--r--src/lib/krb5/keytab/t_keytab.c12
-rw-r--r--src/util/support/errors.c18
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;
}