From e1ef3c298c7fbbf4b1b0a702684b3cdd07591eb1 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 29 Dec 2006 16:38:52 +0000 Subject: [PATCH] Use va_copy() where available. This should fix a segfault in vsnprintf() on AMD 64 Linux. (This has been sitting in my checkout for ages and hasn't obviously caused any trouble -- I think I was waiting to get round to trying it with VC6, which I haven't yet. There are some notes in comments on further tweaks that could be made.) git-svn-id: svn://svn.tartarus.org/sgt/putty@7035 cda61777-01e9-0310-a592-d414129be87e --- misc.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/misc.c b/misc.c index 09506de2..3a275722 100644 --- a/misc.c +++ b/misc.c @@ -180,20 +180,11 @@ char *dupcat(const char *s1, ...) * Do an sprintf(), but into a custom-allocated buffer. * * Currently I'm doing this via vsnprintf. This has worked so far, - * but it's not good, because: - * - * - vsnprintf is not available on all platforms. There's an ifdef - * to use `_vsnprintf', which seems to be the local name for it - * on Windows. Other platforms may lack it completely, in which - * case it'll be time to rewrite this function in a totally - * different way. - * - * - technically you can't reuse a va_list like this: it is left - * unspecified whether advancing a va_list pointer modifies its - * value or something it points to, so on some platforms calling - * vsnprintf twice on the same va_list might fail hideously. It - * would be better to use the `va_copy' macro mandated by C99, - * but that too is not yet ubiquitous. + * but it's not good, because vsnprintf is not available on all + * platforms. There's an ifdef to use `_vsnprintf', which seems + * to be the local name for it on Windows. Other platforms may + * lack it completely, in which case it'll be time to rewrite + * this function in a totally different way. * * The only `properly' portable solution I can think of is to * implement my own format string scanner, which figures out an @@ -241,7 +232,24 @@ char *dupvprintf(const char *fmt, va_list ap) #ifdef _WINDOWS #define vsnprintf _vsnprintf #endif +#ifdef va_copy + /* Use the `va_copy' macro mandated by C99, if present. + * XXX some environments may have this as __va_copy() */ + va_list aq; + va_copy(aq, ap); + len = vsnprintf(buf, size, fmt, aq); + va_end(aq); +#else + /* Ugh. No va_copy macro, so do something nasty. + * Technically, you can't reuse a va_list like this: it is left + * unspecified whether advancing a va_list pointer modifies its + * value or something it points to, so on some platforms calling + * vsnprintf twice on the same va_list might fail hideously + * (indeed, it has been observed to). + * XXX the autoconf manual suggests that using memcpy() will give + * "maximum portability". */ len = vsnprintf(buf, size, fmt, ap); +#endif if (len >= 0 && len < size) { /* This is the C99-specified criterion for snprintf to have * been completely successful. */ -- 2.11.0