aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac4
-rw-r--r--src/estream-printf.c26
-rw-r--r--src/gpgrt-int.h4
-rw-r--r--tests/t-printf.c66
4 files changed, 96 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 392336a..a6a521c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -261,9 +261,11 @@ AC_SUBST(INSTALLSHELLPATH)
# the target system (POSIX or Windows).
# AC_FUNC_FORK
+# Note that vasprintf is only used by the test suite; snprintf is used
+# by estream-printf.c only if available.
AC_CHECK_FUNCS([flockfile vasprintf mmap rand strlwr stpcpy setenv stat \
getrlimit getpwnam getpwuid getpwnam_r getpwuid_r inet_pton \
- getdents64 closefrom])
+ getdents64 closefrom snprintf])
#
diff --git a/src/estream-printf.c b/src/estream-printf.c
index 8e71db7..058ca71 100644
--- a/src/estream-printf.c
+++ b/src/estream-printf.c
@@ -71,6 +71,7 @@
*/
+#define KEEP_SYSTEM_SNPRINTF 1 /* Disable our snprintf re-mapping here. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -1073,7 +1074,7 @@ pr_float (estream_printf_out_t outfnc, void *outfncarg,
int use_dbl = 0;
#endif
double afloat;
- char numbuf[350];
+ char numbuf[450]; /* See comment above the sprintf. */
char formatstr[20];
char *p, *pend;
size_t n;
@@ -1129,9 +1130,30 @@ pr_float (estream_printf_out_t outfnc, void *outfncarg,
if ((arg->flags & FLAG_ALT_CONV))
*--p = '#';
*--p = '%';
+
+ /* On the size of NUMBUF: A double value (e.g. DBL_MAX) can have up
+ * to 309 decimal digits before the decimal point. When formatted
+ * with a precision of 100 (`%.100f`), the resulting string can have
+ * up to 411 characters (309 integer digits + 1 decimal point + 100
+ * fractional digits + 1 nul). With long double it is worse and in
+ * theory we should not use a static buffer but allocate a large
+ * one. However, platforms with support for long double will very
+ * likley also support snprintf which can then be used to throw an
+ * error on truncation. */
#ifdef HAVE_LONG_DOUBLE
if (use_dbl)
- sprintf (numbuf, p, adblfloat);
+ {
+# ifdef HAVE_SNPRINTF
+ rc = snprintf (numbuf, sizeof numbuf, p, adblfloat);
+# else
+ rc = -1; /* Not supported - should not happen. */
+# endif
+ if (rc < 0 || rc >= sizeof numbuf)
+ {
+ _set_errno (EINVAL);
+ return -1;
+ }
+ }
else
#endif /*HAVE_LONG_DOUBLE*/
sprintf (numbuf, p, afloat);
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index f67eec7..d373435 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -480,9 +480,11 @@ const char *_gpgrt_fname_get (gpgrt_stream_t stream);
#include "estream-printf.h"
-/* Make sure we always use our snprintf */
+/* Make sure we always use our snprintf (except for estream-printf.c) */
+#ifndef KEEP_SYSTEM_SNPRINTF
#undef snprintf
#define snprintf _gpgrt_estream_snprintf
+#endif
#if HAVE_W32_SYSTEM
diff --git a/tests/t-printf.c b/tests/t-printf.c
index eb54750..6cbd03f 100644
--- a/tests/t-printf.c
+++ b/tests/t-printf.c
@@ -31,6 +31,7 @@
#include <assert.h>
#include <errno.h>
#include <locale.h>
+#include <float.h>
#define PGM "t-printf"
@@ -418,9 +419,73 @@ check_snprintf (void)
(unsigned int)tmplen, rc, rc2,
(unsigned int)blen, (unsigned int)blen2);
}
+
}
+static void
+check_large_float (void)
+{
+ char *buf, *buf2;
+ double d = DBL_MAX;
+#ifdef HAVE_LONG_DOUBLE
+ long double ld;
+#endif
+
+ errno = ENOENT;
+ buf = gpgrt_bsprintf ("%.100f\n", d);
+ if (!buf)
+ {
+ fail ("format \"%%.100f\" with DBL_MAX failed: errno=%d (%s)\n",
+ errno, strerror (errno));
+ }
+ else if (verbose)
+ show ("format \"%%.100f\" with DBL_MAX: ->%s<-\n", buf);
+
+ buf2 = gpgrt_bsprintf ("%.101f\n", d);
+ if (!buf2)
+ {
+ fail ("format \"%%.101f\" with DBL_MAX failed: errno=%d (%s)\n",
+ errno, strerror (errno));
+ }
+ else if (verbose)
+ show ("format \"%%.100f\" with DBL_MAX: ->%s<-\n", buf2);
+
+ if (strcmp (buf, buf2))
+ fail ("format \"%%.100f\" does not match \"%%.101f\"\n" );
+ gpgrt_free (buf);
+ gpgrt_free (buf2);
+
+#ifdef HAVE_LONG_DOUBLE
+
+ ld = DBL_MAX;
+ buf = gpgrt_bsprintf ("%.100Lf\n", ld);
+ if (!buf)
+ {
+ fail ("format \"%%.100Lf\" with DBL_MAX failed: errno=%d (%s)\n",
+ errno, strerror (errno));
+ }
+ else if (verbose)
+ show ("format \"%%.100Lf\" with DBL_MAX: ->%s<-\n", buf);
+ gpgrt_free (buf);
+
+ ld = LDBL_MAX;
+ buf = gpgrt_bsprintf ("%.100Lf\n", ld);
+ if (buf)
+ {
+ fail ("format \"%%.100Lf\" with LDBL_MAX unexpectly did not fail\n");
+ }
+ else if (verbose)
+ show ("format \"%%.100Lf\" with LDBL_MAX failed as expected\n");
+ gpgrt_free (buf);
+
+#endif /*HAVE_LONG_DOUBLE*/
+}
+
+
+
+
+
struct sfstate_s
{
char *last_result;
@@ -584,6 +649,7 @@ main (int argc, char **argv)
run_tests ();
check_snprintf ();
+ check_large_float ();
check_fprintf_sf ();
check_fwrite ();