#include <openssl/bio.h>
#include <openssl/configuration.h>
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell <papowell@astart.com>
- * 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 = "<NULL>";
-
- 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, ...)
{
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;
}
#include <openssl/bio.h>
#include "internal/nelem.h"
#include "internal/numbers.h"
+#include "internal/bio.h"
#include "testutil.h"
#include "testutil/output.h"
},
};
+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,
{ { .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" },
{ { .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
*/
{ { .i = 0x1337 }, AT_INT, "|%2147483647.x|", "|",
.skip_libc_check = true, .exp_ret = -1 },
+#endif
{ { .i = 0x1337 }, AT_INT,
"abcdefghijklmnopqrstuvwxyz0123456789ZYXWVUTSRQPONMLKJIHGFEDCBA"
"|%4294967295.x|",
{ { .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" },
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);
#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;
{ { .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 },
{ { .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" },
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);
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;
"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 =
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;
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)
/*
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__) */
#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);
#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;
}
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;
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;
{
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 {
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)
} 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)
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,
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;
}
return fflush(stderr);
}
+