The bugfix core in the attached diff are these bits:
@@ -351,6 +361,8 @@
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
+ fmtfp(sbuffer, buffer, &currlen, maxlen,
+ fvalue, min, max, flags); /* [i_a] */
break;
case 'G':
flags |= DP_F_UP;
@@ -359,7 +371,41 @@
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
+ fmtfp(sbuffer, buffer, &currlen, maxlen,
+ fvalue, min, max, flags); /* [i_a] */
^^^ without those fmtfp() calls, you'll never get your %f or %G, etc.
floating point arguments to BIO_printf() et al printed -- up to now,
they were simply silently ignored.
With that comes this additional fix (also in attached diff):
@@ -641,7 +688,7 @@
/* 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));
+ fracpart = roundv(max10 * (ufvalue - intpart)); /* [i_a] */
if (fracpart >= max10) {
intpart++;
which makes sure the fractional part gets calculated correctly, i.e.
shifted by an _integer power of 10_ like it should when you want to
extract particular decimal digits.
The remainder of the patch/diff is a compile-time conditional
alternative for embedded and/or other restricted systems which do not
/ do not want to support floating point printf() support within
OpenSSL. Basically, this is what OpenSSL was doing up to now, though
without the silent skip/ignore of %f,etc. printf() arguments.
Also included are a few assert() --> OPENSSL_assert() fixes.
When you want the 'non-floating point for embedded' code section
(which clearly prints an 'unsupported feature' statement when you try
to print %f, %g, etc. on such a system anyway, which simplifies
problem diagnosis a lot (no silent ignorance), #define that
OPENSSL_NO_FLOAT_SUPPORT in your make environment (I didn't make the
effort to include it as a ./Configure config script option, yet).
>From the accompanying augmented opensslconf.h.in:
-------------
/* crypto/opensslconf.h.in */
/* Generate 80386 code? */
#undef I386_ONLY
+#ifndef OPENSSL_NO_FLOAT_SUPPORT
+/* #define this one if your RTL does not support floating point
printf() formatting options (some embedded OSs / size+feature
reduction) */
+#undef OPENSSL_NO_FLOAT_SUPPORT
+#endif
+
+
----------------
--
Met vriendelijke groeten / Best regards,
Ger Hobbelt
--------------------------------------------------
web: http://www.hobbelt.com/
http://www.hebbut.net/
mail: [email protected]
mobile: +31-6-11 120 978
--------------------------------------------------
--- /home/ger/prj/1original/openssl/openssl/./crypto/bio/b_print.c 2007-09-15 19:05:11.000000000 +0200
+++ ./crypto/bio/b_print.c 2008-12-24 20:04:00.000000000 +0100
@@ -70,7 +70,14 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+
+#if 0 /* [i_a] -- changed every assert() to OPENSSL_assert() */
#include <assert.h>
+#else
+#include <openssl/e_os2.h>
+#include <openssl/crypto.h>
+#endif
+
#include <limits.h>
#include "cryptlib.h"
#ifndef NO_SYS_TYPES_H
@@ -116,7 +123,7 @@
#endif
#ifdef HAVE_LONG_LONG
-# if defined(_WIN32) && !defined(__GNUC__)
+# if defined(OPENSSL_SYS_WIN32) && !defined(__GNUC__)
# define LLONG __int64
# else
# define LLONG long long
@@ -129,8 +136,10 @@
const char *, int, int, int);
static void fmtint (char **, char **, size_t *, size_t *,
LLONG, int, int, int, int);
+#if !defined(OPENSSL_NO_FLOAT_SUPPORT) /* [i_a] */
static void fmtfp (char **, char **, size_t *, size_t *,
LDOUBLE, int, int, int);
+#endif
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,
@@ -336,6 +345,7 @@
ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
min, max, flags);
break;
+#if !defined(OPENSSL_NO_FLOAT_SUPPORT) /* [i_a] */
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg(args, LDOUBLE);
@@ -351,6 +361,8 @@
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
+ fmtfp(sbuffer, buffer, &currlen, maxlen,
+ fvalue, min, max, flags); /* [i_a] */
break;
case 'G':
flags |= DP_F_UP;
@@ -359,7 +371,41 @@
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
+ fmtfp(sbuffer, buffer, &currlen, maxlen,
+ fvalue, min, max, flags); /* [i_a] */
+ break;
+#else /* [i_a] */
+ /* no floating point printf() support! */
+ case 'G':
+ case 'g':
+ case 'E':
+ case 'e':
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg(args, LDOUBLE);
+ else
+ fvalue = va_arg(args, double);
+ /* popped argument; now print 'we do not support this' string */
+ strvalue = "<no floating point support in printf()>";
+ if (max < 0)
+ {
+ if (buffer)
+ max = INT_MAX;
+ else
+ max = *maxlen;
+ }
+ if (max < (int)strlen(strvalue))
+ {
+ strvalue = "NoFP";
+ if (max < (int)strlen(strvalue))
+ {
+ max = strlen(strvalue);
+ }
+ }
+ fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
+ flags, min, max);
break;
+#endif /* [i_a] */
case 'c':
doapr_outch(sbuffer, buffer, &currlen, maxlen,
va_arg(args, int));
@@ -597,6 +643,7 @@
return intpart;
}
+#if !defined(OPENSSL_NO_FLOAT_SUPPORT) /* [i_a] */
static void
fmtfp(
char **sbuffer,
@@ -641,7 +688,7 @@
/* 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));
+ fracpart = roundv(max10 * (ufvalue - intpart)); /* [i_a] */
if (fracpart >= max10) {
intpart++;
@@ -721,6 +768,8 @@
++padlen;
}
}
+#endif /* [i_a] !defined(OPENSSL_NO_FLOAT_SUPPORT) */
+
static void
doapr_outch(
@@ -730,8 +779,8 @@
size_t *maxlen,
int c)
{
- /* If we haven't at least one buffer, someone has doe a big booboo */
- assert(*sbuffer != NULL || buffer != NULL);
+ /* If we haven't at least one buffer, someone has done a big booboo */
+ OPENSSL_assert(*sbuffer != NULL || buffer != NULL);
if (buffer) {
while (*currlen >= *maxlen) {
@@ -740,7 +789,7 @@
*maxlen = 1024;
*buffer = OPENSSL_malloc(*maxlen);
if (*currlen > 0) {
- assert(*sbuffer != NULL);
+ OPENSSL_assert(*sbuffer != NULL);
memcpy(*buffer, *sbuffer, *currlen);
}
*sbuffer = NULL;
@@ -750,7 +799,7 @@
}
}
/* What to do if *buffer is NULL? */
- assert(*sbuffer != NULL || *buffer != NULL);
+ OPENSSL_assert(*sbuffer != NULL || *buffer != NULL);
}
if (*currlen < *maxlen) {
@@ -840,3 +889,66 @@
else
return (retlen <= INT_MAX) ? (int)retlen : -1;
}
+
+
+/* [i_a] */
+
+/* As asnprintf 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?) */
+
+/*
+ Write formatted output to a string dynamically allocated with malloc().
+ You can pass a preallocated buffer for the result in RESULTBUF and its
+ size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+ If successful, return the address of the string (this may be = RESULTBUF
+ if no dynamic memory allocation was necessary) and set *LENGTHP to the
+ number of resulting bytes, excluding the trailing NUL. Upon error, set
+ errno and return NULL.
+
+ When dynamic memory allocation occurs, the preallocated buffer is left
+ alone (with possibly modified contents). This makes it possible to use
+ a statically allocated or stack-allocated buffer, like this:
+
+ char buf[100];
+ size_t len = sizeof(buf);
+ char *output = vasnprintf (buf, &len, format, args);
+ if (output == NULL)
+ ... error handling ...;
+ else
+ {
+ ... use the output string ...;
+ if (output != buf)
+ OPENSSL_free(output);
+ }
+ */
+char *BIO_asnprintf(char *buf, size_t *n, const char *format, ...)
+ {
+ va_list args;
+ char *ret;
+
+ va_start(args, format);
+
+ ret = BIO_vasnprintf(buf, n, format, args);
+
+ va_end(args);
+ return(ret);
+ }
+
+char *BIO_vasnprintf(char *buf, size_t *n_ref, const char *format, va_list args)
+ {
+ size_t retlen;
+ char *dynbuf = NULL;
+ int ignored;
+
+ CRYPTO_push_info("BIO_vasnprintf()");
+ _dopr(&buf, &dynbuf, n_ref, &retlen, &ignored, format, args);
+ if (!dynbuf)
+ {
+ dynbuf = buf;
+ }
+ *n_ref = retlen;
+ CRYPTO_pop_info();
+ return dynbuf;
+ }