X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fb_print.c;h=143a7cfefa37e201bc5bd11d53fac7cd23dff17f;hp=caf2235cc273b21d80edfb89f2132c7dd2fabd00;hb=77519b51dbfe8652dad58536f6fa21a089080c1d;hpb=a1990dd76d07d2ad9d2d32666ec6022bd23da6aa diff --git a/crypto/bio/b_print.c b/crypto/bio/b_print.c index caf2235cc2..143a7cfefa 100644 --- a/crypto/bio/b_print.c +++ b/crypto/bio/b_print.c @@ -56,47 +56,36 @@ * [including the GNU Public Licence.] */ +/* disable assert() unless BIO_DEBUG has been defined */ +#ifndef BIO_DEBUG +# ifndef NDEBUG +# define NDEBUG +# endif +#endif + /* * Stolen from tjh's ssl/ssl_trc.c stuff. */ #include -#include #include #include +#include +#include #include "cryptlib.h" #ifndef NO_SYS_TYPES_H #include #endif +#include /* To get BN_LLONG properly defined */ #include -#ifdef BN_LLONG +#if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT) # ifndef HAVE_LONG_LONG -# define HAVE_LONG_LONG +# define HAVE_LONG_LONG 1 # endif #endif -static void dopr (char *buffer, size_t maxlen, size_t *retlen, - const char *format, va_list args); - -int BIO_printf (BIO *bio, ...) - { - va_list args; - char *format; - int ret; - size_t retlen; - MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */ - - va_start(args, bio); - format=va_arg(args, char *); - - hugebuf[0]='\0'; - dopr(hugebuf, sizeof(hugebuf), &retlen, format, args); - ret=BIO_write(bio, hugebuf, (int)retlen); - - va_end(args); - return(ret); - } +/***************************************************************************/ /* * Copyright Patrick Powell 1995 @@ -117,24 +106,35 @@ int BIO_printf (BIO *bio, ...) * o Andrew Tridgell (1998, for Samba) * o Luke Mewburn (1999, for LukemFTP) * o Ralf S. Engelschall (1999, for Pth) + * o ... (for OpenSSL) */ -#if HAVE_LONG_DOUBLE +#ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif -#if HAVE_LONG_LONG -#define LLONG long long +#ifdef HAVE_LONG_LONG +# if defined(_WIN32) && !defined(__GNUC__) +# define LLONG __int64 +# else +# define LLONG long long +# endif #else #define LLONG long #endif -static void fmtstr (char *, size_t *, size_t, char *, int, int, int); -static void fmtint (char *, size_t *, size_t, LLONG, int, int, int, int); -static void fmtfp (char *, size_t *, size_t, LDOUBLE, int, int, int); -static void dopr_outch (char *, size_t *, size_t, int); +static void fmtstr (char **, char **, size_t *, size_t *, + const char *, int, int, int); +static void fmtint (char **, char **, size_t *, size_t *, + LLONG, int, int, int, int); +static void fmtfp (char **, char **, size_t *, size_t *, + LDOUBLE, int, int, int); +static void doapr_outch (char **, char **, size_t *, size_t *, int); +static void _dopr(char **sbuffer, char **buffer, + size_t *maxlen, size_t *retlen, int *truncated, + const char *format, va_list args); /* format read states */ #define DP_S_DEFAULT 0 @@ -163,13 +163,15 @@ static void dopr_outch (char *, size_t *, size_t, int); /* some handy macros */ #define char_to_int(p) (p - '0') -#define MAX(p,q) ((p >= q) ? p : q) +#define OSSL_MAX(p,q) ((p >= q) ? p : q) static void -dopr( - char *buffer, - size_t maxlen, +_dopr( + char **sbuffer, + char **buffer, + size_t *maxlen, size_t *retlen, + int *truncated, const char *format, va_list args) { @@ -190,7 +192,7 @@ dopr( ch = *format++; while (state != DP_S_DONE) { - if ((ch == '\0') || (currlen >= maxlen)) + if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) state = DP_S_DONE; switch (state) { @@ -198,7 +200,7 @@ dopr( if (ch == '%') state = DP_S_FLAGS; else - dopr_outch(buffer, &currlen, maxlen, ch); + doapr_outch(sbuffer,buffer, &currlen, maxlen, ch); ch = *format++; break; case DP_S_FLAGS: @@ -292,7 +294,7 @@ dopr( case 'i': switch (cflags) { case DP_C_SHORT: - value = va_arg(args, short int); + value = (short int)va_arg(args, int); break; case DP_C_LONG: value = va_arg(args, long int); @@ -304,7 +306,8 @@ dopr( value = va_arg(args, int); break; } - fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); + fmtint(sbuffer, buffer, &currlen, maxlen, + value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; @@ -315,8 +318,7 @@ dopr( flags |= DP_F_UNSIGNED; switch (cflags) { case DP_C_SHORT: - value = va_arg(args, - unsigned short int); + value = (unsigned short int)va_arg(args, unsigned int); break; case DP_C_LONG: value = (LLONG) va_arg(args, @@ -330,7 +332,7 @@ dopr( unsigned int); break; } - fmtint(buffer, &currlen, maxlen, value, + fmtint(sbuffer, buffer, &currlen, maxlen, value, ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), min, max, flags); break; @@ -339,7 +341,8 @@ dopr( fvalue = va_arg(args, LDOUBLE); else fvalue = va_arg(args, double); - fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); + fmtfp(sbuffer, buffer, &currlen, maxlen, + fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; @@ -358,20 +361,24 @@ dopr( fvalue = va_arg(args, double); break; case 'c': - dopr_outch(buffer, &currlen, maxlen, + doapr_outch(sbuffer, buffer, &currlen, maxlen, va_arg(args, int)); break; case 's': strvalue = va_arg(args, char *); - if (max < 0) - max = maxlen; - fmtstr(buffer, &currlen, maxlen, strvalue, - flags, min, max); + if (max < 0) { + if (buffer) + max = INT_MAX; + else + max = *maxlen; + } + fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, + flags, min, max); break; case 'p': value = (long)va_arg(args, void *); - fmtint(buffer, &currlen, maxlen, - value, 16, min, max, flags); + fmtint(sbuffer, buffer, &currlen, maxlen, + value, 16, min, max, flags|DP_F_NUM); break; case 'n': /* XXX */ if (cflags == DP_C_SHORT) { @@ -393,7 +400,7 @@ dopr( } break; case '%': - dopr_outch(buffer, &currlen, maxlen, ch); + doapr_outch(sbuffer, buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ @@ -414,19 +421,21 @@ dopr( break; } } - if (currlen >= maxlen - 1) - currlen = maxlen - 1; - buffer[currlen] = '\0'; - *retlen = currlen; + *truncated = (currlen > *maxlen - 1); + if (*truncated) + currlen = *maxlen - 1; + doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'); + *retlen = currlen - 1; return; } static void fmtstr( - char *buffer, + char **sbuffer, + char **buffer, size_t *currlen, - size_t maxlen, - char *value, + size_t *maxlen, + const char *value, int flags, int min, int max) @@ -445,16 +454,16 @@ fmtstr( padlen = -padlen; while ((padlen > 0) && (cnt < max)) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { - dopr_outch(buffer, currlen, maxlen, *value++); + doapr_outch(sbuffer, buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); ++padlen; ++cnt; } @@ -462,9 +471,10 @@ fmtstr( static void fmtint( - char *buffer, + char **sbuffer, + char **buffer, size_t *currlen, - size_t maxlen, + size_t *maxlen, LLONG value, int base, int min, @@ -472,8 +482,9 @@ fmtint( int flags) { int signvalue = 0; + const char *prefix = ""; unsigned LLONG uvalue; - char convert[20]; + char convert[DECIMAL_SIZE(value)+3]; int place = 0; int spadlen = 0; int zpadlen = 0; @@ -491,6 +502,10 @@ fmtint( else if (flags & DP_F_SPACE) signvalue = ' '; } + if (flags & DP_F_NUM) { + if (base == 8) prefix = "0"; + if (base == 16) prefix = "0x"; + } if (flags & DP_F_UP) caps = 1; do { @@ -498,19 +513,19 @@ fmtint( (caps ? "0123456789ABCDEF" : "0123456789abcdef") [uvalue % (unsigned) base]; uvalue = (uvalue / (unsigned) base); - } while (uvalue && (place < 20)); - if (place == 20) + } while (uvalue && (place < (int)sizeof(convert))); + if (place == sizeof(convert)) place--; convert[place] = 0; zpadlen = max - place; - spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); + spadlen = min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { - zpadlen = MAX(zpadlen, spadlen); + zpadlen = OSSL_MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) @@ -518,28 +533,34 @@ fmtint( /* spaces */ while (spadlen > 0) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); --spadlen; } /* sign */ if (signvalue) - dopr_outch(buffer, currlen, maxlen, signvalue); + doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); + + /* prefix */ + while (*prefix) { + doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix); + prefix++; + } /* zeros */ if (zpadlen > 0) { while (zpadlen > 0) { - dopr_outch(buffer, currlen, maxlen, '0'); + doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); --zpadlen; } } /* digits */ while (place > 0) - dopr_outch(buffer, currlen, maxlen, convert[--place]); + doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]); /* left justified spaces */ while (spadlen < 0) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); ++spadlen; } return; @@ -555,18 +576,18 @@ abs_val(LDOUBLE value) } static LDOUBLE -pow10(int exp) +pow_10(int in_exp) { LDOUBLE result = 1; - while (exp) { + while (in_exp) { result *= 10; - exp--; + in_exp--; } return result; } static long -round(LDOUBLE value) +roundv(LDOUBLE value) { long intpart; intpart = (long) value; @@ -578,9 +599,10 @@ round(LDOUBLE value) static void fmtfp( - char *buffer, + char **sbuffer, + char **buffer, size_t *currlen, - size_t maxlen, + size_t *maxlen, LDOUBLE fvalue, int min, int max, @@ -597,6 +619,7 @@ fmtfp( int caps = 0; long intpart; long fracpart; + long max10; if (max < 0) max = 6; @@ -617,11 +640,12 @@ fmtfp( /* we "cheat" by converting the fractional part to integer by multiplying by a factor of 10 */ - fracpart = round((pow10(max)) * (ufvalue - intpart)); + max10 = roundv(pow_10(max)); + fracpart = roundv(pow_10(max) * (ufvalue - intpart)); - if (fracpart >= pow10(max)) { + if (fracpart >= max10) { intpart++; - fracpart -= (long)pow10(max); + fracpart -= max10; } /* convert integer part */ @@ -630,8 +654,8 @@ fmtfp( (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10]; intpart = (intpart / 10); - } while (intpart && (iplace < 20)); - if (iplace == 20) + } while (intpart && (iplace < (int)sizeof(iconvert))); + if (iplace == sizeof iconvert) iplace--; iconvert[iplace] = 0; @@ -641,8 +665,8 @@ fmtfp( (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10]; fracpart = (fracpart / 10); - } while (fracpart && (fplace < 20)); - if (fplace == 20) + } while (fplace < max); + if (fplace == sizeof fconvert) fplace--; fconvert[fplace] = 0; @@ -658,54 +682,161 @@ fmtfp( if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { - dopr_outch(buffer, currlen, maxlen, signvalue); + doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { - dopr_outch(buffer, currlen, maxlen, '0'); + doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) - dopr_outch(buffer, currlen, maxlen, signvalue); + doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); while (iplace > 0) - dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); + doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]); /* * Decimal point. This should probably use locale to find the correct * char to print out. */ - if (max > 0) { - dopr_outch(buffer, currlen, maxlen, '.'); + if (max > 0 || (flags & DP_F_NUM)) { + doapr_outch(sbuffer, buffer, currlen, maxlen, '.'); while (fplace > 0) - dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); + doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]); } while (zpadlen > 0) { - dopr_outch(buffer, currlen, maxlen, '0'); + doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { - dopr_outch(buffer, currlen, maxlen, ' '); + doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); ++padlen; } } static void -dopr_outch( - char *buffer, +doapr_outch( + char **sbuffer, + char **buffer, size_t *currlen, - size_t maxlen, + size_t *maxlen, int c) { - if (*currlen < maxlen) - buffer[(*currlen)++] = (char)c; + /* If we haven't at least one buffer, someone has doe a big booboo */ + assert(*sbuffer != NULL || buffer != NULL); + + if (buffer) { + while (*currlen >= *maxlen) { + if (*buffer == NULL) { + if (*maxlen == 0) + *maxlen = 1024; + *buffer = OPENSSL_malloc(*maxlen); + if (*currlen > 0) { + assert(*sbuffer != NULL); + memcpy(*buffer, *sbuffer, *currlen); + } + *sbuffer = NULL; + } else { + *maxlen += 1024; + *buffer = OPENSSL_realloc(*buffer, *maxlen); + } + } + /* What to do if *buffer is NULL? */ + assert(*sbuffer != NULL || *buffer != NULL); + } + + if (*currlen < *maxlen) { + if (*sbuffer) + (*sbuffer)[(*currlen)++] = (char)c; + else + (*buffer)[(*currlen)++] = (char)c; + } + return; } + +/***************************************************************************/ + +int BIO_printf (BIO *bio, const char *format, ...) + { + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vprintf(bio, format, args); + + va_end(args); + return(ret); + } + +int BIO_vprintf (BIO *bio, const char *format, va_list args) + { + int ret; + size_t retlen; + char hugebuf[1024*2]; /* Was previously 10k, which is unreasonable + in small-stack environments, like threads + or DOS programs. */ + char *hugebufp = hugebuf; + size_t hugebufsize = sizeof(hugebuf); + char *dynbuf = NULL; + int ignored; + + dynbuf = NULL; + CRYPTO_push_info("doapr()"); + _dopr(&hugebufp, &dynbuf, &hugebufsize, + &retlen, &ignored, format, args); + if (dynbuf) + { + ret=BIO_write(bio, dynbuf, (int)retlen); + OPENSSL_free(dynbuf); + } + else + { + ret=BIO_write(bio, hugebuf, (int)retlen); + } + CRYPTO_pop_info(); + return(ret); + } + +/* As snprintf is not available everywhere, we provide our own implementation. + * This function has nothing to do with BIOs, but it's closely related + * to BIO_printf, and we need *some* name prefix ... + * (XXX the function should be renamed, but to what?) */ +int BIO_snprintf(char *buf, size_t n, const char *format, ...) + { + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vsnprintf(buf, n, format, args); + + va_end(args); + return(ret); + } + +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) + { + size_t retlen; + int truncated; + + _dopr(&buf, NULL, &n, &retlen, &truncated, format, args); + + if (truncated) + /* In case of truncation, return -1 like traditional snprintf. + * (Current drafts for ISO/IEC 9899 say snprintf should return + * the number of characters that would have been written, + * had the buffer been large enough.) */ + return -1; + else + return (retlen <= INT_MAX) ? (int)retlen : -1; + }