From: Nikos Mavrogiannopoulos Date: Thu, 4 Sep 2014 11:48:20 +0000 (+0200) Subject: steal openconnect's vasprintf() implementation X-Git-Tag: gnutls_3_4_0~991 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=57741bb040ff962a90fc9fb91683dcf3dc1ed4d8;p=thirdparty%2Fgnutls.git steal openconnect's vasprintf() implementation --- diff --git a/configure.ac b/configure.ac index 8a776d5200..65eade2d7b 100644 --- a/configure.ac +++ b/configure.ac @@ -156,6 +156,29 @@ AC_C_BIGENDIAN dnl No fork on MinGW, disable some self-tests until we fix them. dnl Check clock_gettime and pthread_mutex_lock in libc (avoid linking to other libs) AC_CHECK_FUNCS([fork inet_ntop inet_pton getrusage getpwuid_r nanosleep daemon getpid clock_gettime iconv localtime vasprintf],,) +if test "$ac_cv_func_vasprintf" != "yes";then + AC_MSG_CHECKING([for va_copy]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + #include + va_list a;],[ + va_list b; + va_copy(b,a); + va_end(b);])], + [AC_DEFINE(HAVE_VA_COPY, 1, [Have va_copy()]) + AC_MSG_RESULT(va_copy)], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([ + #include + va_list a;],[ + va_list b; + __va_copy(b,a); + va_end(b);])], + [AC_DEFINE(HAVE___VA_COPY, 1, [Have __va_copy()]) + AC_MSG_RESULT(__va_copy)], + [AC_MSG_RESULT(no) + AC_MSG_ERROR([Your system lacks vasprintf() and va_copy()])]) + ]) +fi + AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no") AC_CHECK_FUNCS([pthread_atfork __register_atfork],,) diff --git a/lib/vasprintf.c b/lib/vasprintf.c index f2eeb89b4f..8362942a20 100644 --- a/lib/vasprintf.c +++ b/lib/vasprintf.c @@ -1,31 +1,83 @@ +/* + * Copyright © 2008-2014 Intel Corporation. + * + * Authors: David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1, as published by the Free Software Foundation. + * + * 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 + * Lesser General Public License for more details. + */ + #include #include +#include +#include +#include #include "vasprintf.h" #ifndef HAVE_VASPRINTF -#define MAX_BSIZE 1024 -#define NO_MORE_MAX (16*MAX_BSIZE) - int _gnutls_vasprintf(char **strp, const char *fmt, va_list ap) { - char *buf; - int ret, max; + va_list ap2; + char *res = NULL; + int len = 160, len2; + int ret = 0; + int errno_save = -ENOMEM; - max = MAX_BSIZE / 2; + res = malloc(160); + if (!res) + goto err; - do { - max *= 2; - - buf = malloc(max); - if (buf == NULL) - return -1; + /* Use a copy of 'ap', preserving it in case we need to retry into + a larger buffer. 160 characters should be sufficient for most + strings in openconnect. */ +#ifdef HAVE_VA_COPY + va_copy(ap2, ap); +#elif defined(HAVE___VA_COPY) + __va_copy(ap2, ap); +#else +#error No va_copy()! + /* You could try this. */ + ap2 = ap; + /* Or this */ + *ap2 = *ap; +#endif + len = vsnprintf(res, 160, fmt, ap2); + va_end(ap2); - ret = vsnprintf(buf, max, fmt, ap); + if (len < 0) { + printf_err: + errno_save = errno; + free(res); + res = NULL; + goto err; } - while (ret > max && max < NO_MORE_MAX); - *strp = buf; + if (len >= 0 && len < 160) + goto out; + + free(res); + res = malloc(len+1); + if (!res) + goto err; + + len2 = vsnprintf(res, len+1, fmt, ap); + if (len2 < 0 || len2 > len) + goto printf_err; + + ret = 0; + goto out; + err: + errno = errno_save; + ret = -1; + out: + *strp = res; return ret; }