diff options
| -rw-r--r-- | configure.ac | 4 | ||||
| -rw-r--r-- | src/estream-printf.c | 26 | ||||
| -rw-r--r-- | src/gpgrt-int.h | 4 | ||||
| -rw-r--r-- | tests/t-printf.c | 66 |
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 (); |
