From a29d157fdb6d5260888b4505c11f0d360fab16f8 Mon Sep 17 00:00:00 2001 From: sashan Date: Fri, 11 Apr 2025 22:42:08 +0200 Subject: [PATCH] Replace homebrewed implementation of *printf*() functions with libc Switching from ANSI-C we can use implementation of printf like function provided by libc on target platform. This applies starting from 3.6 and onwards. The slight exception here is old windows printf functions before 2015, those are supported. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/28305) --- crypto/bio/bio_print.c | 1099 +++--------------------- include/internal/bio.h | 4 + test/bioprinttest.c | 366 ++++---- test/build.info | 6 +- util/platform_symbols/unix-symbols.txt | 1 + 5 files changed, 297 insertions(+), 1179 deletions(-) diff --git a/crypto/bio/bio_print.c b/crypto/bio/bio_print.c index c2db1fa6c11..06ffdf74c6e 100644 --- a/crypto/bio/bio_print.c +++ b/crypto/bio/bio_print.c @@ -15,1016 +15,128 @@ #include #include -/* - * Copyright Patrick Powell 1995 - * This code is based on code written by Patrick Powell - * It may be used for any purpose as long as this notice remains intact - * on all source code distributions. - */ - -#ifdef HAVE_LONG_DOUBLE -# define LDOUBLE long double -#else -# define LDOUBLE double -#endif - -struct pr_desc { - /** Static buffer */ - char *sbuffer; - /** Dynamic buffer */ - char **buffer; - /** Current writing position */ - size_t currlen; - /** Buffer size */ - size_t maxlen; - /** "Write position", for proper %n support */ - long long pos; -}; - -static int fmtstr(struct pr_desc *, const char *, int, int, int); -static int fmtint(struct pr_desc *, int64_t, int, int, int, int); -#ifndef OPENSSL_SYS_UEFI -static int fmtfp(struct pr_desc *, LDOUBLE, int, int, int, int); -#endif -static int doapr_outch(struct pr_desc *, int); -static int _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 -#define DP_S_FLAGS 1 -#define DP_S_MIN 2 -#define DP_S_DOT 3 -#define DP_S_MAX 4 -#define DP_S_MOD 5 -#define DP_S_CONV 6 -#define DP_S_DONE 7 - -/* format flags - Bits */ -/* left-aligned padding */ -#define DP_F_MINUS (1 << 0) -/* print an explicit '+' for a value with positive sign */ -#define DP_F_PLUS (1 << 1) -/* print an explicit ' ' for a value with positive sign */ -#define DP_F_SPACE (1 << 2) -/* print 0/0x prefix for octal/hex and decimal point for floating point */ -#define DP_F_NUM (1 << 3) -/* print leading zeroes */ -#define DP_F_ZERO (1 << 4) -/* print HEX in UPPERcase */ -#define DP_F_UP (1 << 5) -/* treat value as unsigned */ -#define DP_F_UNSIGNED (1 << 6) - -/* conversion flags */ -#define DP_C_CHAR 1 -#define DP_C_SHORT 2 -#define DP_C_LONG 3 -#define DP_C_LDOUBLE 4 -#define DP_C_LLONG 5 -#define DP_C_SIZE 6 -#define DP_C_PTRDIFF 7 - -/* Floating point formats */ -#define F_FORMAT 0 -#define E_FORMAT 1 -#define G_FORMAT 2 - -/* some handy macros */ -#define char_to_int(p) (p - '0') -#define OSSL_MAX(p,q) ((p >= q) ? p : q) -static int -_dopr(char **sbuffer, - char **buffer, - size_t *maxlen, - size_t *retlen, int *truncated, const char *format, va_list args) +int BIO_printf(BIO *bio, const char *format, ...) { - char ch; - int64_t value; -#ifndef OPENSSL_SYS_UEFI - LDOUBLE fvalue; -#endif - char *strvalue; - int min; - int max; - int state; - int flags; - int cflags; - struct pr_desc desc = { *sbuffer, buffer, 0, *maxlen, 0 }; - int ret = 0; - - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - ch = *format++; - - while (state != DP_S_DONE) { - if (ch == '\0') - state = DP_S_DONE; - - switch (state) { - case DP_S_DEFAULT: - if (ch == '%') - state = DP_S_FLAGS; - else - if (!doapr_outch(&desc, ch)) - goto out; - ch = *format++; - break; - case DP_S_FLAGS: - switch (ch) { - case '-': - flags |= DP_F_MINUS; - ch = *format++; - break; - case '+': - flags |= DP_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= DP_F_SPACE; - ch = *format++; - break; - case '#': - flags |= DP_F_NUM; - ch = *format++; - break; - case '0': - flags |= DP_F_ZERO; - ch = *format++; - break; - default: - state = DP_S_MIN; - break; - } - break; - case DP_S_MIN: /* width */ - if (ossl_isdigit(ch)) { - /* - * Most implementations cap the possible explicitly specified - * width by (INT_MAX / 10) * 10 - 1 or so (the standard gives - * no clear limit on this), we can do the same. - */ - if (min < INT_MAX / 10) - min = 10 * min + char_to_int(ch); - else - goto out; - ch = *format++; - } else if (ch == '*') { - min = va_arg(args, int); - if (min < 0) { - flags |= DP_F_MINUS; - min = -min; - } - ch = *format++; - state = DP_S_DOT; - } else - state = DP_S_DOT; - break; - case DP_S_DOT: - if (ch == '.') { - state = DP_S_MAX; - ch = *format++; - } else - state = DP_S_MOD; - break; - case DP_S_MAX: /* precision */ - if (ossl_isdigit(ch)) { - if (max < 0) - max = 0; - /* - * Most implementations cap the possible explicitly specified - * width by (INT_MAX / 10) * 10 - 1 or so (the standard gives - * no clear limit on this), we can do the same. - */ - if (max < INT_MAX / 10) - max = 10 * max + char_to_int(ch); - else - goto out; - ch = *format++; - } else if (ch == '*') { - max = va_arg(args, int); - ch = *format++; - state = DP_S_MOD; - } else { - if (max < 0) - max = 0; - state = DP_S_MOD; - } - break; - case DP_S_MOD: - switch (ch) { - case 'h': - if (*format == 'h') { - cflags = DP_C_CHAR; - format++; - } else { - cflags = DP_C_SHORT; - } - ch = *format++; - break; - case 'l': - if (*format == 'l') { - cflags = DP_C_LLONG; - format++; - } else - cflags = DP_C_LONG; - ch = *format++; - break; - case 'q': - case 'j': - cflags = DP_C_LLONG; - ch = *format++; - break; - case 'L': - cflags = DP_C_LDOUBLE; - ch = *format++; - break; - case 'z': - cflags = DP_C_SIZE; - ch = *format++; - break; - case 't': - cflags = DP_C_PTRDIFF; - ch = *format++; - break; - default: - break; - } - state = DP_S_CONV; - break; - case DP_S_CONV: - switch (ch) { - case 'd': - case 'i': - switch (cflags) { - case DP_C_CHAR: - value = (signed char)va_arg(args, int); - break; - case DP_C_SHORT: - value = (short int)va_arg(args, int); - break; - case DP_C_LONG: - value = va_arg(args, long int); - break; - case DP_C_LLONG: - value = va_arg(args, int64_t); - break; - case DP_C_SIZE: - value = va_arg(args, ossl_ssize_t); - break; - case DP_C_PTRDIFF: - value = va_arg(args, ptrdiff_t); - break; - default: - value = va_arg(args, int); - break; - } - if (!fmtint(&desc, value, 10, min, max, flags)) - goto out; - break; - case 'X': - flags |= DP_F_UP; - /* FALLTHROUGH */ - case 'x': - case 'o': - case 'u': - flags |= DP_F_UNSIGNED; - switch (cflags) { - case DP_C_CHAR: - value = (unsigned char)va_arg(args, unsigned int); - break; - case DP_C_SHORT: - value = (unsigned short int)va_arg(args, unsigned int); - break; - case DP_C_LONG: - value = va_arg(args, unsigned long int); - break; - case DP_C_LLONG: - value = va_arg(args, uint64_t); - break; - case DP_C_SIZE: - value = va_arg(args, size_t); - break; - case DP_C_PTRDIFF: - /* - * There is no unsigned variant of ptrdiff_t, and POSIX - * requires using a "corresponding unsigned type argument". - * Assuming it is power of two in size, at least. - */ - if (sizeof(ptrdiff_t) == sizeof(uint64_t)) - value = va_arg(args, uint64_t); - else - value = va_arg(args, unsigned int); - break; - default: - value = va_arg(args, unsigned int); - break; - } - if (!fmtint(&desc, value, - ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), - min, max, flags)) - goto out; - break; -#ifndef OPENSSL_SYS_UEFI - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(&desc, fvalue, min, max, flags, F_FORMAT)) - goto out; - break; - case 'E': - flags |= DP_F_UP; - /* fall through */ - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(&desc, fvalue, min, max, flags, E_FORMAT)) - goto out; - break; - case 'G': - flags |= DP_F_UP; - /* fall through */ - case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(&desc, fvalue, min, max, flags, G_FORMAT)) - goto out; - break; -#else - case 'f': - case 'E': - case 'e': - case 'G': - case 'g': - /* not implemented for UEFI */ - ERR_raise(ERR_LIB_BIO, ERR_R_UNSUPPORTED); - goto out; -#endif - case 'c': - if (!doapr_outch(&desc, va_arg(args, int))) - goto out; - break; - case 's': - strvalue = va_arg(args, char *); - if (max < 0) - max = INT_MAX; - if (!fmtstr(&desc, strvalue, flags, min, max)) - goto out; - break; - case 'p': - value = (size_t)va_arg(args, void *); - if (!fmtint(&desc, value, 16, min, max, flags | DP_F_NUM)) - goto out; - break; - case 'n': - switch (cflags) { -#define HANDLE_N(type) \ - do { \ - type *num; \ - \ - num = va_arg(args, type *); \ - *num = (type) desc.pos; \ - } while (0) - case DP_C_CHAR: - HANDLE_N(signed char); - break; - case DP_C_SHORT: - HANDLE_N(short); - break; - case DP_C_LONG: - HANDLE_N(long); - break; - case DP_C_LLONG: - HANDLE_N(long long); - break; - case DP_C_SIZE: - HANDLE_N(ossl_ssize_t); - break; - case DP_C_PTRDIFF: - HANDLE_N(ptrdiff_t); - break; - default: - HANDLE_N(int); - break; -#undef HANDLE_N - } - break; - case '%': - if (!doapr_outch(&desc, ch)) - goto out; - break; - case 'w': - /* not supported yet, treat as next char */ - format++; - break; - default: - /* unknown, skip */ - break; - } - ch = *format++; - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - break; - case DP_S_DONE: - break; - default: - break; - } - } - ret = 1; - -out: - /* - * We have to truncate if there is no dynamic buffer and we have filled the - * static buffer. - */ - if (buffer == NULL) { - *truncated = (desc.currlen > desc.maxlen - 1); - if (*truncated) - desc.currlen = desc.maxlen - 1; - } + va_list args; + int ret; - if (!doapr_outch(&desc, '\0')) - ret = 0; + va_start(args, format); - *retlen = desc.currlen - 1; - *sbuffer = desc.sbuffer; - *maxlen = desc.maxlen; + ret = BIO_vprintf(bio, format, args); + va_end(args); return ret; } -static int -fmtstr(struct pr_desc *desc, const char *value, int flags, int min, int max) -{ - int padlen; - size_t strln; - int cnt = 0; - - if (value == 0) - value = ""; - - strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max); - - padlen = (int)(min - strln); - if (min < 0 || padlen < 0) - padlen = 0; - if (max >= 0) { - /* - * Calculate the maximum output including padding. - * Make sure max doesn't overflow into negativity - */ - if (max < INT_MAX - padlen) - max += padlen; - else - max = INT_MAX; - } - if (flags & DP_F_MINUS) - padlen = -padlen; - - while ((padlen > 0) && (max < 0 || cnt < max)) { - if (!doapr_outch(desc, ' ')) - return 0; - --padlen; - ++cnt; - } - while (strln > 0 && (max < 0 || cnt < max)) { - if (!doapr_outch(desc, *value++)) - return 0; - --strln; - ++cnt; - } - while ((padlen < 0) && (max < 0 || cnt < max)) { - if (!doapr_outch(desc, ' ')) - return 0; - ++padlen; - ++cnt; - } - return 1; -} - -static int -fmtint(struct pr_desc *desc, - int64_t value, int base, int min, int max, int flags) -{ - static const char oct_prefix[] = "0"; - - int signvalue = 0; - const char *prefix = ""; - uint64_t uvalue; - char convert[DECIMAL_SIZE(value) + 3]; - int place = 0; - int spadlen = 0; - int zpadlen = 0; - int caps = 0; - - if (max < 0) { - /* A negative precision is taken as if the precision were omitted. */ - max = 1; - } else { - /* - * If a precision is given with an integer conversion, - * the 0 flag is ignored. - */ - flags &= ~DP_F_ZERO; - } - uvalue = value; - if (!(flags & DP_F_UNSIGNED)) { - if (value < 0) { - signvalue = '-'; - uvalue = 0 - (uint64_t)value; - } else if (flags & DP_F_PLUS) - signvalue = '+'; - else if (flags & DP_F_SPACE) - signvalue = ' '; - } - if (flags & DP_F_NUM) { - if (base == 8) - prefix = oct_prefix; - if (value != 0) { - if (base == 16) - prefix = flags & DP_F_UP ? "0X" : "0x"; - } - } - if (flags & DP_F_UP) - caps = 1; - /* When 0 is printed with an explicit precision 0, the output is empty. */ - while (uvalue && (place < (int)sizeof(convert))) { - convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") - [uvalue % (unsigned)base]; - uvalue = (uvalue / (unsigned)base); - } - if (place == sizeof(convert)) - place--; - convert[place] = 0; - - /* - * "#" (alternative form): - * - For o conversion, it shall increase the precision, if and only - * if necessary, to force the first digit of the result to be a zero - */ - zpadlen = max - place - (prefix == oct_prefix); - if (zpadlen < 0) - zpadlen = 0; - spadlen = - min - OSSL_MAX(max, place + zpadlen + (signvalue ? 1 : 0) + (int)strlen(prefix)); - if (spadlen < 0) - spadlen = 0; - if (flags & DP_F_MINUS) { - spadlen = -spadlen; - } else if (flags & DP_F_ZERO) { - zpadlen = zpadlen + spadlen; - spadlen = 0; - } - - /* spaces */ - while (spadlen > 0) { - if (!doapr_outch(desc, ' ')) - return 0; - --spadlen; - } - - /* sign */ - if (signvalue) - if (!doapr_outch(desc, signvalue)) - return 0; - - /* prefix */ - while (*prefix) { - if (!doapr_outch(desc, *prefix)) - return 0; - prefix++; - } - - /* zeros */ - if (zpadlen > 0) { - while (zpadlen > 0) { - if (!doapr_outch(desc, '0')) - return 0; - --zpadlen; - } - } - /* digits */ - while (place > 0) { - if (!doapr_outch(desc, convert[--place])) - return 0; - } - - /* left justified spaces */ - while (spadlen < 0) { - if (!doapr_outch(desc, ' ')) - return 0; - ++spadlen; - } - return 1; -} - -#ifndef OPENSSL_SYS_UEFI - -static LDOUBLE abs_val(LDOUBLE value) -{ - LDOUBLE result = value; - if (value < 0) - result = -value; - if (result > 0 && result / 2 == result) /* INF */ - result = 0; - else if (result != result) /* NAN */ - result = 0; - return result; -} - -static LDOUBLE pow_10(int in_exp) -{ - LDOUBLE result = 1; - while (in_exp) { - result *= 10; - in_exp--; - } - return result; -} - -static long roundv(LDOUBLE value) -{ - long intpart; - intpart = (long)value; - value = value - intpart; - if (value >= 0.5) - intpart++; - return intpart; -} - -static int -fmtfp(struct pr_desc *desc, - LDOUBLE fvalue, int min, int max, int flags, int style) +#if defined(_WIN32) +/* + * _MSC_VER described here: + * https://learn.microsoft.com/en-us/cpp/overview/compiler-versions?view=msvc-170 + * + * Beginning with the UCRT in Visual Studio 2015 and Windows 10, snprintf is no + * longer identical to _snprintf. The snprintf behavior is now C99 standard + * conformant. The difference is that if you run out of buffer, snprintf + * null-terminates the end of the buffer and returns the number of characters + * that would have been required whereas _snprintf doesn't null-terminate the + * buffer and returns -1. Also, snprintf() includes one more character in the + * output because it doesn't null-terminate the buffer. + * [ https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/snprintf-snprintf-snprintf-l-snwprintf-snwprintf-l?view=msvc-170#remarks + * + * for older MSVC (older than 2015) we can use _vscprintf() and _vsnprintf() + * as suggested here: + * https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + * + */ +static int msvc_bio_vprintf(BIO *bio, const char *format, va_list args) { - int signvalue = 0; - LDOUBLE ufvalue; - LDOUBLE tmpvalue; - char iconvert[20]; - char fconvert[20]; - char econvert[20]; - int iplace = 0; - int fplace = 0; - int eplace = 0; - int padlen = 0; - int zpadlen = 0; - long exp = 0; - unsigned long intpart; - unsigned long fracpart; - unsigned long max10; - int realstyle; - - if (max < 0) - max = 6; - - if (fvalue < 0) - signvalue = '-'; - else if (flags & DP_F_PLUS) - signvalue = '+'; - else if (flags & DP_F_SPACE) - signvalue = ' '; - ufvalue = abs_val(fvalue); - if (ufvalue == 0 && fvalue != 0) /* INF or NAN? */ - signvalue = '?'; - - /* - * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT - * depending on the number to be printed. Work out which one it is and use - * that from here on. - */ - if (style == G_FORMAT) { - if (ufvalue == 0.0) { - realstyle = F_FORMAT; - } else if (ufvalue < 0.0001) { - realstyle = E_FORMAT; - } else if ((max == 0 && ufvalue >= 10) - || (max > 0 && ufvalue >= pow_10(max))) { - realstyle = E_FORMAT; + char buf[512]; + char *abuf; + int ret, sz; + + sz = _vsnprintf_s(buf, sizeof (buf), _TRUNCATE, format, args); + if (sz == -1) { + sz = _vscprintf(format, args) + 1; + abuf = (char *) OPENSSL_malloc(sz); + if (abuf == NULL) { + ret = -1; } else { - realstyle = F_FORMAT; + sz = _vsnprintf(abuf, sz, format, args); + ret = BIO_write(bio, abuf, sz); + OPENSSL_free(abuf); } } else { - realstyle = style; + ret = BIO_write(bio, buf, sz); } - if (style != F_FORMAT) { - tmpvalue = ufvalue; - /* Calculate the exponent */ - if (ufvalue != 0.0) { - while (tmpvalue < 1) { - tmpvalue *= 10; - exp--; - } - while (tmpvalue > 10) { - tmpvalue /= 10; - exp++; - } - } - if (style == G_FORMAT) { - /* - * In G_FORMAT the "precision" represents significant digits. We - * always have at least 1 significant digit. - */ - if (max == 0) - max = 1; - /* Now convert significant digits to decimal places */ - if (realstyle == F_FORMAT) { - max -= (exp + 1); - if (max < 0) { - /* - * Should not happen. If we're in F_FORMAT then exp < max? - */ - (void)doapr_outch(desc, '\0'); - return 0; - } - } else { - /* - * In E_FORMAT there is always one significant digit in front - * of the decimal point, so: - * significant digits == 1 + decimal places - */ - max--; - } - } - if (realstyle == E_FORMAT) - ufvalue = tmpvalue; - } - - /* - * By subtracting 65535 (2^16-1) we cancel the low order 15 bits - * of ULONG_MAX to avoid using imprecise floating point values. - */ - if (ufvalue >= (double)(ULONG_MAX - 65535) + 65536.0) { - /* Number too big */ - (void)doapr_outch(desc, '\0'); - return 0; - } - intpart = (unsigned long)ufvalue; - - /* - * sorry, we only support 9 digits past the decimal because of our - * conversion method - */ - if (max > 9) - max = 9; - - /* - * we "cheat" by converting the fractional part to integer by multiplying - * by a factor of 10 - */ - max10 = roundv(pow_10(max)); - fracpart = roundv(pow_10(max) * (ufvalue - intpart)); - - if (fracpart >= max10) { - intpart++; - fracpart -= max10; - } - - /* convert integer part */ - do { - iconvert[iplace++] = "0123456789"[intpart % 10]; - intpart = (intpart / 10); - } while (intpart && (iplace < (int)sizeof(iconvert))); - if (iplace == sizeof(iconvert)) - iplace--; - iconvert[iplace] = 0; - - /* convert fractional part */ - while (fplace < max) { - if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) { - /* We strip trailing zeros in G_FORMAT */ - max--; - fracpart = fracpart / 10; - if (fplace < max) - continue; - break; - } - fconvert[fplace++] = "0123456789"[fracpart % 10]; - fracpart = (fracpart / 10); - } - - fconvert[fplace] = 0; - - /* convert exponent part */ - if (realstyle == E_FORMAT) { - int tmpexp; - if (exp < 0) - tmpexp = -exp; - else - tmpexp = exp; - - do { - econvert[eplace++] = "0123456789"[tmpexp % 10]; - tmpexp = (tmpexp / 10); - } while (tmpexp > 0 && eplace < (int)sizeof(econvert)); - /* Exponent is huge!! Too big to print */ - if (tmpexp > 0) { - (void)doapr_outch(desc, '\0'); - return 0; - } - /* Add a leading 0 for single digit exponents */ - if (eplace == 1) - econvert[eplace++] = '0'; - } - - /* - * -1 for decimal point (if we have one, i.e. max > 0), - * another -1 if we are printing a sign - */ - padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0); - /* Take some off for exponent prefix "+e" and exponent */ - if (realstyle == E_FORMAT) - padlen -= 2 + eplace; - zpadlen = max - fplace; - if (zpadlen < 0) - zpadlen = 0; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; - - if ((flags & DP_F_ZERO) && (padlen > 0)) { - if (signvalue) { - if (!doapr_outch(desc, signvalue)) - return 0; - --padlen; - signvalue = 0; - } - while (padlen > 0) { - if (!doapr_outch(desc, '0')) - return 0; - --padlen; - } - } - while (padlen > 0) { - if (!doapr_outch(desc, ' ')) - return 0; - --padlen; - } - if (signvalue && !doapr_outch(desc, signvalue)) - return 0; - - while (iplace > 0) { - if (!doapr_outch(desc, iconvert[--iplace])) - return 0; - } - - /* - * Decimal point. This should probably use locale to find the correct - * char to print out. - */ - if (max > 0 || (flags & DP_F_NUM)) { - if (!doapr_outch(desc, '.')) - return 0; - - while (fplace > 0) { - if (!doapr_outch(desc, fconvert[--fplace])) - return 0; - } - } - while (zpadlen > 0) { - if (!doapr_outch(desc, '0')) - return 0; - --zpadlen; - } - if (realstyle == E_FORMAT) { - char ech; - - if ((flags & DP_F_UP) == 0) - ech = 'e'; - else - ech = 'E'; - if (!doapr_outch(desc, ech)) - return 0; - if (exp < 0) { - if (!doapr_outch(desc, '-')) - return 0; - } else { - if (!doapr_outch(desc, '+')) - return 0; - } - while (eplace > 0) { - if (!doapr_outch(desc, econvert[--eplace])) - return 0; - } - } - - while (padlen < 0) { - if (!doapr_outch(desc, ' ')) - return 0; - ++padlen; - } - return 1; -} - -#endif /* OPENSSL_SYS_UEFI */ - -#define BUFFER_INC 1024 - -static int -doapr_outch(struct pr_desc *desc, int c) -{ - /* If we haven't at least one buffer, someone has done a big booboo */ - if (!ossl_assert(desc->sbuffer != NULL || desc->buffer != NULL)) - return 0; - - /* |currlen| must always be <= |*maxlen| */ - if (!ossl_assert(desc->currlen <= desc->maxlen)) - return 0; - - if (desc->buffer != NULL && desc->currlen == desc->maxlen) { - if (desc->maxlen > INT_MAX - BUFFER_INC) - return 0; - - desc->maxlen += BUFFER_INC; - if (*(desc->buffer) == NULL) { - if ((*(desc->buffer) = OPENSSL_malloc(desc->maxlen)) == NULL) - return 0; - if (desc->currlen > 0) { - if (!ossl_assert(desc->sbuffer != NULL)) - return 0; - memcpy(*(desc->buffer), desc->sbuffer, desc->currlen); - } - desc->sbuffer = NULL; - } else { - char *tmpbuf; - - tmpbuf = OPENSSL_realloc(*(desc->buffer), desc->maxlen); - if (tmpbuf == NULL) - return 0; - *(desc->buffer) = tmpbuf; - } - } - - if (desc->currlen < desc->maxlen) { - if (desc->sbuffer) - (desc->sbuffer)[(desc->currlen)++] = (char)c; - else - (*(desc->buffer))[(desc->currlen)++] = (char)c; - } - - desc->pos++; - - return 1; + return ret; } -/***************************************************************************/ - -int BIO_printf(BIO *bio, const char *format, ...) +/* + * This function is for unit test on windows only when built with Visual Studio + */ +int ossl_BIO_snprintf_msvc(char *buf, size_t n, const char *format, ...) { va_list args; int ret; va_start(args, format); - - ret = BIO_vprintf(bio, format, args); - + ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); va_end(args); + return ret; } +#endif + 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; + va_list cp_args; +#if !defined(_MSC_VER) || _MSC_VER > 1900 + int sz; +#endif + int ret = -1; - dynbuf = NULL; - if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format, - args)) { - OPENSSL_free(dynbuf); - return -1; - } - if (dynbuf) { - ret = BIO_write(bio, dynbuf, (int)retlen); - OPENSSL_free(dynbuf); - } else { - ret = BIO_write(bio, hugebuf, (int)retlen); + va_copy(cp_args, args); +#if defined(_MSC_VER) && _MSC_VER < 1900 + ret = msvc_bio_vprintf(bio, format, cp_args); +#else + char buf[512]; + char *abuf; + /* + * some compilers modify va_list, hence each call to v*printf() + * should operate with its own instance of va_list. The first + * call to vsnprintf() here uses args we got in function argument. + * The second call is going to use cp_args we made earlier. + */ + sz = vsnprintf(buf, sizeof (buf), format, args); + if (sz >= 0) { + if ((size_t)sz > sizeof (buf)) { + sz += 1; + abuf = (char *) OPENSSL_malloc(sz); + if (abuf == NULL) { + ret = -1; + } else { + sz = vsnprintf(abuf, sz, format, cp_args); + ret = BIO_write(bio, abuf, sz); + OPENSSL_free(abuf); + } + } else { + /* vsnprintf returns length not including nul-terminator */ + ret = BIO_write(bio, buf, sz); + } } +#endif + va_end(cp_args); 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?) + * For historical reasons BIO_snprintf and friends return a failure for string + * truncation (-1) instead of the POSIX requirement of a success with the + * number of characters that would have been written. Upon seeing -1 on + * return, the caller must treat output buf as unsafe (as a buf with missing + * nul terminator). */ int BIO_snprintf(char *buf, size_t n, const char *format, ...) { @@ -1033,27 +145,28 @@ int BIO_snprintf(char *buf, size_t n, const char *format, ...) va_start(args, format); - ret = BIO_vsnprintf(buf, n, format, args); - +#if defined(_MSC_VER) && _MSC_VER < 1900 + ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); +#else + ret = vsnprintf(buf, n, format, args); + if ((size_t)ret >= n) + ret = -1; +#endif va_end(args); + return ret; } int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) { - size_t retlen; - int truncated; - - if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args)) - return -1; + int ret; - 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; - return (retlen <= INT_MAX) ? (int)retlen : -1; +#if defined(_MSC_VER) && _MSC_VER < 1900 + ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); +#else + ret = vsnprintf(buf, n, format, args); + if ((size_t)ret >= n) + ret = -1; +#endif + return ret; } diff --git a/include/internal/bio.h b/include/internal/bio.h index 9481f4c985e..1de0fe7f563 100644 --- a/include/internal/bio.h +++ b/include/internal/bio.h @@ -98,4 +98,8 @@ int ossl_core_bio_vprintf(OSSL_CORE_BIO *cb, const char *format, va_list args); int ossl_bio_init_core(OSSL_LIB_CTX *libctx, const OSSL_DISPATCH *fns); +# ifdef _WIN32 +int ossl_BIO_snprintf_msvc(char *buf, size_t n, const char *fmt, ...); +# endif + #endif diff --git a/test/bioprinttest.c b/test/bioprinttest.c index a2e107b62df..5e4e414a546 100644 --- a/test/bioprinttest.c +++ b/test/bioprinttest.c @@ -16,6 +16,7 @@ #include #include "internal/nelem.h" #include "internal/numbers.h" +#include "internal/bio.h" #include "testutil.h" #include "testutil/output.h" @@ -115,6 +116,8 @@ static const char * const fpexpected[][11][5] = { }, }; +static int(*test_BIO_snprintf)(char *, size_t, const char *, ...) = BIO_snprintf; + enum arg_type { AT_NONE = 0, AT_CHAR, AT_SHORT, AT_INT, AT_LONG, AT_LLONG, @@ -162,7 +165,9 @@ static const struct int_data { { { .hh = 0x0 }, AT_CHAR, "%02hhx", "00" }, { { .h = 0 }, AT_SHORT, "|%.0hd|", "||" }, { { .h = 0 }, AT_SHORT, "|%.hu|", "||" }, +#if !defined(__OpenBSD__) { { .h = 0 }, AT_SHORT, "|%#.ho|", "|0|" }, +#endif { { .h = 1 }, AT_SHORT, "%4.2hi", " 01" }, { { .h = 2 }, AT_SHORT, "%-4.3hu", "002 " }, { { .h = 3 }, AT_SHORT, "%+.3hu", "003" }, @@ -194,12 +199,12 @@ static const struct int_data { { { .i = 0x1337 }, AT_INT, "|%2147483639.x|", "| ", .skip_libc_ret_check = true, .exp_ret = -1 }, +#if !defined(OPENSSL_SYS_WINDOWS) + /* + * those test crash on x86 windows built by VS-2019 + */ { { .i = 0x1337 }, AT_INT, "|%.2147483639x|", "|00000000000000000000000000000000000000000000000000000000000000", -#if defined(OPENSSL_SYS_WINDOWS) - /* MS CRT can't handle this one, snprintf() causes access violation. */ - .skip_libc_check = true, -#endif .skip_libc_ret_check = true, .exp_ret = -1 }, /* * We treat the following three format strings as errneous and bail out @@ -207,6 +212,7 @@ static const struct int_data { */ { { .i = 0x1337 }, AT_INT, "|%2147483647.x|", "|", .skip_libc_check = true, .exp_ret = -1 }, +#endif { { .i = 0x1337 }, AT_INT, "abcdefghijklmnopqrstuvwxyz0123456789ZYXWVUTSRQPONMLKJIHGFEDCBA" "|%4294967295.x|", @@ -215,7 +221,9 @@ static const struct int_data { { { .i = 0x1337 }, AT_INT, "%4294967302.x", "", .skip_libc_check = true, .exp_ret = -1 }, { { .i = 0xbeeface }, AT_INT, "%#+-12.1d", "+200211150 " }, +#if !defined(__OpenBSD__) { { .l = 0 }, AT_LONG, "%%%#.0lo%%", "%0%" }, +#endif { { .l = 0 }, AT_LONG, "%%%.0lo%%", "%%" }, { { .l = 0 }, AT_LONG, "%%%-.0lo%%", "%%" }, { { .l = 0xfacefed }, AT_LONG, "%#-1.14ld", "00000262991853" }, @@ -234,24 +242,18 @@ static const struct int_data { static int test_int(int i) { char bio_buf[64]; - char std_buf[64]; int bio_ret; - int std_ret = 0; const struct int_data *data = int_data + i; const int exp_ret = data->exp_ret ? data->exp_ret : (int) strlen(data->expected); memset(bio_buf, '@', sizeof(bio_buf)); - memset(std_buf, '#', sizeof(std_buf)); switch (data->type) { -#define DO_PRINT(field_) \ - do { \ - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, \ - data->value.field_); \ - if (!data->skip_libc_check) \ - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, \ - data->value.field_); \ +#define DO_PRINT(field_) \ + do { \ + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, \ + data->value.field_); \ } while (0) case AT_CHAR: DO_PRINT(hh); @@ -274,29 +276,32 @@ static int test_int(int i) #undef DO_PRINT } - if (!TEST_str_eq(bio_buf, data->expected) + if (data->skip_libc_check) { + if (strcmp(bio_buf, data->expected) != 0) + TEST_note("%s Result (%s) does not match (%s)", __func__, + bio_buf, data->expected); + } else if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) { TEST_note("Format: \"%s\"", data->format); return 0; } - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!data->skip_libc_check) { - if (!TEST_str_eq(bio_buf, std_buf) - + !(data->skip_libc_ret_check || TEST_int_eq(bio_ret, std_ret))) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - } - return 1; } +#ifdef _WIN32 +static int test_int_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_int(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + union ptrint { uintptr_t i; const char *s; @@ -321,7 +326,9 @@ static const struct wp_data { { { .i = 0 }, "|%#*" PRIoPTR "|", "| 0|", 1, 2 }, { { .i = 0 }, "|%#.*" PRIoPTR "|", "|00|", 1, 2 }, { { .i = 0 }, "|%#.*" PRIoPTR "|", "|0|", 1, 1 }, +#if !defined(__OpenBSD__) { { .i = 0 }, "|%#.*" PRIoPTR "|", "|0|", 1, 0 }, +#endif { { .i = 0 }, "|%.*" PRIoPTR "|", "||", 1, 0 }, { { .i = 0 }, "|%#.*" PRIoPTR "|", "|0|", 1, -12 }, @@ -336,12 +343,14 @@ static const struct wp_data { { { .i = 1337 }, "|%*" PRIuPTR "|", "| ", 1, 2147483647, .skip_libc_check = true, .exp_ret = -1 }, +#if !defined(OPENSSL_SYS_WINDOWS) { { .i = 1337 }, "|%.*" PRIuPTR "|", "|00000000000000000000000000000000000000000000000000000000000000", 1, 2147483647, .skip_libc_check = true, .exp_ret = -1 }, { { .i = 1337 }, "|%#*.*" PRIoPTR "|", "| 0", 2, 2147483647, 2147483586, .skip_libc_check = true, .exp_ret = -1 }, +#endif /* String width/precision checks */ { { .s = "01234" }, "%12s", " 01234" }, @@ -382,7 +391,6 @@ static int test_width_precision(int i) char bio_buf[64]; char std_buf[64]; int bio_ret; - int std_ret = 0; const struct wp_data *data = wp_data + i; const int exp_ret = data->exp_ret ? data->exp_ret : (int) strlen(data->expected); @@ -392,53 +400,47 @@ static int test_width_precision(int i) switch (data->num_args) { case 2: - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, - data->arg1, data->arg2, data->value.i); - if (!data->skip_libc_check) - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, - data->arg1, data->arg2, data->value.i); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, + data->arg1, data->arg2, data->value.i); break; case 1: - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, - data->arg1, data->value.i); - if (!data->skip_libc_check) - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, - data->arg1, data->value.i); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, + data->arg1, data->value.i); break; case 0: default: - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, - data->value.i); - if (!data->skip_libc_check) - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, - data->value.i); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, + data->value.i); } - if (!TEST_str_eq(bio_buf, data->expected) + if (data->skip_libc_check) { + if (strcmp(bio_buf, data->expected) != 0) + TEST_note("%s Result (%s) does not match (%s)", __func__, + bio_buf, data->expected); + } else if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) { TEST_note("Format: \"%s\"", data->format); return 0; } - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal, unless OPENSSL_STRICT_PRINTF_COMPLIANCE_CHECK is defined. - */ - if (!data->skip_libc_check) { - if (!TEST_str_eq(bio_buf, std_buf) - + !(data->skip_libc_ret_check || TEST_int_eq(bio_ret, std_ret))) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - } - return 1; } +#ifdef _WIN32 +static int test_width_precision_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_width_precision(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + static const struct n_data { const char *format; const char *expected; @@ -477,14 +479,13 @@ static const struct n_data { "1234567890 ", AT_SHORT, -7616, AT_INT, { .s = "1234567890" }, .skip_libc_ret_check = true, .exp_ret = -1 }, +#if !defined(OPENSSL_SYS_WINDOWS) { "%1234567898.1234567890" PRIxPTR "%n", " 0000000000000000000000000000000000000000000000000000000", AT_INT, 1234567898, AT_INT, { .i = 0xbadc0ded }, -#if defined(OPENSSL_SYS_WINDOWS) /* MS CRT can't handle this one, snprintf() causes access violation. */ - .skip_libc_check = true, -#endif .skip_libc_ret_check = true, .exp_ret = -1 }, +#endif { "%s|%n", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|", AT_INT, 63, AT_STR, { .s = @@ -529,8 +530,6 @@ static int test_n(int i) char bio_buf[64]; char std_buf[64]; int bio_ret; - int std_ret = 0; - bool skip_libc_check = data->skip_libc_check; union { uint64_t val; signed char hh; @@ -540,8 +539,7 @@ static int test_n(int i) long long int ll; ossl_ssize_t z; ptrdiff_t t; - } n = { 0 }, std_n = { 0 }; - uint64_t n_val, std_n_val; + } n = { 0 }; #if defined(OPENSSL_SYS_WINDOWS) /* @@ -553,20 +551,18 @@ static int test_n(int i) if (_get_printf_count_output() == 0) { TEST_note("Can't enable %%n handling for snprintf" ", skipping the checks against libc"); - skip_libc_check = true; } #elif defined(__OpenBSD__) { static bool note_printed; if (!note_printed) { - TEST_note("OpenBSD libc unconditionally terminates a program " + TEST_note("OpenBSD libc unconditionally aborts a program " "if %%n is used in a *printf routine" ", skipping the checks against libc"); note_printed = true; } - - skip_libc_check = true; + return 1; } #endif /* defined(OPENSSL_SYS_WINDOWS) || defined(__OpenBSD__) */ @@ -577,26 +573,15 @@ static int test_n(int i) #define DO_PRINT(field_) \ do { \ if (data->arg1_type == AT_NONE) { \ - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, \ - &n.field_); \ - if (!skip_libc_check) \ - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, \ - &std_n.field_); \ + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format,\ + &n.field_); \ } else if (data->arg2_type == AT_NONE) { \ - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, \ - data->arg1.i, &n.field_); \ - if (!skip_libc_check) \ - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, \ - data->arg1.i, &std_n.field_); \ + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format,\ + data->arg1.i, &n.field_); \ } else { \ - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, \ - data->arg1.i, data->arg2.i, &n.field_); \ - if (!skip_libc_check) \ - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, \ - data->arg1.i, data->arg2.i, &std_n.field_); \ + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format,\ + data->arg1.i, data->arg2.i, &n.field_);\ } \ - n_val = n.field_; \ - std_n_val = std_n.field_; \ } while (0) case AT_CHAR: DO_PRINT(hh); @@ -625,28 +610,16 @@ static int test_n(int i) #undef DO_PRINT } - if (!TEST_str_eq(bio_buf, data->expected) - + !TEST_uint64_t_eq(n_val, data->exp_n) + if (data->skip_libc_check) { + if (strcmp(bio_buf, data->expected) != 0) + TEST_note("%s Result (%s) does not match (%s)", __func__, + bio_buf, data->expected); + } else if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) { TEST_note("Format: \"%s\"", data->format); return 0; } - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!data->skip_libc_check) { - if (!TEST_str_eq(bio_buf, std_buf) - + !TEST_uint64_t_eq(n_val, std_n_val) - + !(data->skip_libc_ret_check || TEST_int_eq(bio_ret, std_ret))) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - } - return 1; } @@ -674,36 +647,33 @@ static const z_data zu_data[] = { static int test_zu(int i) { char bio_buf[80]; - char std_buf[80]; const z_data *data = &zu_data[i]; const int exp_ret = (int) strlen(data->expected); int bio_ret; - int std_ret; memset(bio_buf, '@', sizeof(bio_buf)); - memset(std_buf, '#', sizeof(std_buf)); - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, data->value); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) return 0; - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!TEST_str_eq(bio_buf, std_buf) - + !TEST_int_eq(bio_ret, std_ret)) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - return 1; } +#ifdef _WIN32 +static int test_zu_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_zu(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + static const struct t_data { size_t value; const char *format; @@ -720,36 +690,33 @@ static const struct t_data { static int test_t(int i) { char bio_buf[64]; - char std_buf[64]; const struct t_data *data = &t_data[i]; const int exp_ret = (int) strlen(data->expected); int bio_ret; - int std_ret; memset(bio_buf, '@', sizeof(bio_buf)); - memset(std_buf, '#', sizeof(std_buf)); - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, data->value); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) return 0; - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!TEST_str_eq(bio_buf, std_buf) - + !TEST_int_eq(bio_ret, std_ret)) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - return 1; } +#ifdef _WIN32 +static int test_t_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_t(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + typedef struct j_data_st { uint64_t value; const char *format; @@ -771,35 +738,31 @@ static int test_j(int i) { const j_data *data = &jf_data[i]; char bio_buf[80]; - char std_buf[80]; const int exp_ret = (int) strlen(data->expected); int bio_ret; - int std_ret; memset(bio_buf, '@', sizeof(bio_buf)); - memset(std_buf, '#', sizeof(std_buf)); - bio_ret = BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); - std_ret = snprintf(std_buf, sizeof(std_buf), data->format, data->value); + bio_ret = test_BIO_snprintf(bio_buf, sizeof(bio_buf), data->format, data->value); if (!TEST_str_eq(bio_buf, data->expected) + !TEST_int_eq(bio_ret, exp_ret)) return 0; - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!TEST_str_eq(bio_buf, std_buf) - + !TEST_int_eq(bio_ret, std_ret)) { - TEST_note("Format: \"%s\"", data->format); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - return 0; -#endif - } - return 1; } +#ifdef _WIN32 +static int test_j_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_j(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif /* Precision and width. */ typedef struct pw_st { @@ -822,27 +785,24 @@ static int dofptest(int test, int sub, double val, const char *width, int prec) static const char *fspecs[] = { "e", "f", "g", "E", "G" }; - char format[80], result[80], std_result[80]; + char format[80], result[80]; int ret = 1, i; int exp_ret; int bio_ret; - int std_ret; for (i = 0; i < (int)OSSL_NELEM(fspecs); i++) { const char *fspec = fspecs[i]; memset(result, '@', sizeof(result)); - memset(std_result, '#', sizeof(std_result)); if (prec >= 0) - BIO_snprintf(format, sizeof(format), "%%%s.%d%s", width, prec, - fspec); + test_BIO_snprintf(format, sizeof(format), "%%%s.%d%s", width, prec, + fspec); else - BIO_snprintf(format, sizeof(format), "%%%s%s", width, fspec); + test_BIO_snprintf(format, sizeof(format), "%%%s%s", width, fspec); exp_ret = (int) strlen(fpexpected[test][sub][i]); - bio_ret = BIO_snprintf(result, sizeof(result), format, val); - std_ret = snprintf(std_result, sizeof(std_result), format, val); + bio_ret = test_BIO_snprintf(result, sizeof(result), format, val); if (justprint) { if (i == 0) @@ -852,27 +812,10 @@ static int dofptest(int test, int sub, double val, const char *width, int prec) } else { if (!TEST_str_eq(fpexpected[test][sub][i], result) + !TEST_int_eq(bio_ret, exp_ret)) { - TEST_info("test %d format=|%s| exp=|%s|, ret=|%s|" - ", stdlib_ret=|%s|", - test, format, fpexpected[test][sub][i], result, - std_result); + TEST_info("test %d format=|%s| exp=|%s|, ret=|%s|", + test, format, fpexpected[test][sub][i], result); ret = 0; } - - /* - * We treat the unexpected discrepancies with libc results as notable, - * but not fatal. - */ - if (!TEST_str_eq(result, std_result) - + !TEST_int_eq(bio_ret, std_ret)) { - TEST_info("test %d format=|%s| exp=|%s|, ret=|%s|" - ", stdlib_ret=|%s|", - test, format, fpexpected[test][sub][i], result, - std_result); -#if defined(OPENSSL_STRICT_LIBC_PRINTF_CHECK) - ret = 0; -#endif - } } } if (justprint) @@ -904,18 +847,49 @@ static int test_fp(int i) return r; } +#ifdef _WIN32 +static int test_fp_win32(int i) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_fp(i); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + static int test_big(void) { char buf[80]; +#ifdef _WIN32 +#define EXPECTED 18 +#else +#define EXPECTED 28 +#endif /* Test excessively big number. Should fail */ - if (!TEST_int_eq(BIO_snprintf(buf, sizeof(buf), - "%f\n", 2 * (double)ULONG_MAX), -1)) + if (!TEST_int_eq(test_BIO_snprintf(buf, sizeof(buf), + "%f\n", 2 * (double)ULONG_MAX), EXPECTED)) return 0; return 1; } +#ifdef _WIN32 +static int test_big_win32(void) +{ + int ret; + + test_BIO_snprintf = ossl_BIO_snprintf_msvc; + ret = test_big(); + test_BIO_snprintf = BIO_snprintf; + + return ret; +} +#endif + typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, @@ -957,6 +931,27 @@ int setup_tests(void) ADD_ALL_TESTS(test_zu, OSSL_NELEM(zu_data)); ADD_ALL_TESTS(test_t, OSSL_NELEM(t_data)); ADD_ALL_TESTS(test_j, OSSL_NELEM(jf_data)); + +#ifdef _WIN32 + /* + * those tests are using _vsnprintf_s() + */ + ADD_TEST(test_big_win32); + ADD_ALL_TESTS(test_fp_win32, OSSL_NELEM(pw_params)); + ADD_ALL_TESTS(test_int_win32, OSSL_NELEM(int_data)); + ADD_ALL_TESTS(test_width_precision_win32, OSSL_NELEM(wp_data)); + /* + * test_n() which uses "%n" format string triggers + * an assert 'Incorrect format specifier' found in + * minkernel\crts\ucrt\correct_internal_stdio_output.h + * (line 1690). + * Therefore we don't add test_n() here. + */ + ADD_ALL_TESTS(test_zu_win32, OSSL_NELEM(zu_data)); + ADD_ALL_TESTS(test_t_win32, OSSL_NELEM(t_data)); + ADD_ALL_TESTS(test_j_win32, OSSL_NELEM(jf_data)); +#endif + return 1; } @@ -1027,3 +1022,4 @@ int test_flush_taperr(void) return fflush(stderr); } + diff --git a/test/build.info b/test/build.info index d9cc4dae9ce..8b581763b56 100644 --- a/test/build.info +++ b/test/build.info @@ -548,7 +548,11 @@ IF[{- !$disabled{tests} -}] SOURCE[bioprinttest]=bioprinttest.c INCLUDE[bioprinttest]=../include ../apps/include - DEPEND[bioprinttest]=../libcrypto libtestutil.a + IF[{- $config{target} =~ /^VC/ -}] + DEPEND[bioprinttest]=../libcrypto.a libtestutil.a + ELSE + DEPEND[bioprinttest]=../libcrypto libtestutil.a + ENDIF SOURCE[bio_core_test]=bio_core_test.c INCLUDE[bio_core_test]=../include ../apps/include diff --git a/util/platform_symbols/unix-symbols.txt b/util/platform_symbols/unix-symbols.txt index d5d70802564..166bc5d8dfe 100644 --- a/util/platform_symbols/unix-symbols.txt +++ b/util/platform_symbols/unix-symbols.txt @@ -160,4 +160,5 @@ __timezone uname usleep vfprintf +vsnprintf __xpg_strerror_r -- 2.47.3