In 6275f5d28a1577563f53f2171689d4f890a46881, we fixed warnings from the
options -Wformat-overflow and -Wformat-truncation, which are part of
-Wall in gcc 7.

Here, I propose to dial this up a bit by adding -Wformat-overflow=2
-Wformat-truncation=2, which use some more worst-case approaches for
estimating the buffer sizes.

AFAICT, the issues addressed here either can't really happen without
trying very hard, or would cause harmless output truncation.  Still, it
seems good to clean this up properly and not rely on made-up buffer size
guesses that turn out to be wrong, even if we don't want to adopt the
warning options by default.

One issue that is of external interest is that I increase BGW_MAXLEN
from 64 to 96.  Apparently, the old value would cause the bgw_name of
logical replication workers to be truncated in some circumstances.  I
have also seen truncated background worker names with third-party
packages, so giving some more room here would be useful.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 99316e6db5a98f5daaaf61a75a01b88e7b2f39bf Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Wed, 28 Feb 2018 23:11:24 -0500
Subject: [PATCH] Fix more format truncation issues

Add compiler warning options -Wformat-overflow=2 -Wformat-truncation=2,
supported since GCC 7, and fix the warnings that they create.

The issues are all harmless, but some dubious coding patterns are
cleaned up.
---
 configure                                | 71 ++++++++++++++++++++++++++++++++
 configure.in                             |  3 ++
 contrib/pgstattuple/pgstattuple.c        |  2 +-
 src/backend/commands/explain.c           |  5 ++-
 src/backend/utils/adt/dbsize.c           |  2 +-
 src/backend/utils/adt/float.c            | 24 +++++------
 src/backend/utils/adt/formatting.c       | 33 +++++----------
 src/backend/utils/misc/guc.c             |  4 +-
 src/bin/initdb/initdb.c                  |  6 +--
 src/bin/pg_dump/pg_backup_archiver.c     |  2 +-
 src/bin/pg_dump/pg_backup_tar.c          |  2 +-
 src/bin/pgbench/pgbench.c                |  4 +-
 src/include/postmaster/bgworker.h        |  2 +-
 src/interfaces/libpq/fe-secure-openssl.c |  2 +-
 src/pl/tcl/pltcl.c                       |  2 +-
 15 files changed, 111 insertions(+), 53 deletions(-)

diff --git a/configure b/configure
index 7dcca506f8..48a7546513 100755
--- a/configure
+++ b/configure
@@ -4595,6 +4595,77 @@ if test x"$pgac_cv_prog_cc_cflags__Wformat_security" = 
x"yes"; then
   CFLAGS="$CFLAGS -Wformat-security"
 fi
 
+  # gcc 7+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports 
-Wformat-overflow=2" >&5
+$as_echo_n "checking whether $CC supports -Wformat-overflow=2... " >&6; }
+if ${pgac_cv_prog_cc_cflags__Wformat_overflow_2+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  pgac_save_CFLAGS=$CFLAGS
+CFLAGS="$pgac_save_CFLAGS -Wformat-overflow=2"
+ac_save_c_werror_flag=$ac_c_werror_flag
+ac_c_werror_flag=yes
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  pgac_cv_prog_cc_cflags__Wformat_overflow_2=yes
+else
+  pgac_cv_prog_cc_cflags__Wformat_overflow_2=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_c_werror_flag=$ac_save_c_werror_flag
+CFLAGS="$pgac_save_CFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$pgac_cv_prog_cc_cflags__Wformat_overflow_2" >&5
+$as_echo "$pgac_cv_prog_cc_cflags__Wformat_overflow_2" >&6; }
+if test x"$pgac_cv_prog_cc_cflags__Wformat_overflow_2" = x"yes"; then
+  CFLAGS="$CFLAGS -Wformat-overflow=2"
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports 
-Wformat-truncation=2" >&5
+$as_echo_n "checking whether $CC supports -Wformat-truncation=2... " >&6; }
+if ${pgac_cv_prog_cc_cflags__Wformat_truncation_2+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  pgac_save_CFLAGS=$CFLAGS
+CFLAGS="$pgac_save_CFLAGS -Wformat-truncation=2"
+ac_save_c_werror_flag=$ac_c_werror_flag
+ac_c_werror_flag=yes
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  pgac_cv_prog_cc_cflags__Wformat_truncation_2=yes
+else
+  pgac_cv_prog_cc_cflags__Wformat_truncation_2=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_c_werror_flag=$ac_save_c_werror_flag
+CFLAGS="$pgac_save_CFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$pgac_cv_prog_cc_cflags__Wformat_truncation_2" >&5
+$as_echo "$pgac_cv_prog_cc_cflags__Wformat_truncation_2" >&6; }
+if test x"$pgac_cv_prog_cc_cflags__Wformat_truncation_2" = x"yes"; then
+  CFLAGS="$CFLAGS -Wformat-truncation=2"
+fi
+
   # Disable strict-aliasing rules; needed for gcc 3.3+
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports 
-fno-strict-aliasing" >&5
 $as_echo_n "checking whether $CC supports -fno-strict-aliasing... " >&6; }
diff --git a/configure.in b/configure.in
index 4d26034579..d46194235f 100644
--- a/configure.in
+++ b/configure.in
@@ -425,6 +425,9 @@ if test "$GCC" = yes -a "$ICC" = no; then
   PGAC_PROG_CC_CFLAGS_OPT([-Wmissing-format-attribute])
   # This was included in -Wall/-Wformat in older GCC versions
   PGAC_PROG_CC_CFLAGS_OPT([-Wformat-security])
+  # gcc 7+
+  PGAC_PROG_CC_CFLAGS_OPT([-Wformat-overflow=2])
+  PGAC_PROG_CC_CFLAGS_OPT([-Wformat-truncation=2])
   # Disable strict-aliasing rules; needed for gcc 3.3+
   PGAC_PROG_CC_CFLAGS_OPT([-fno-strict-aliasing])
   # Disable optimizations that assume no overflow; needed for gcc 4.3+
diff --git a/contrib/pgstattuple/pgstattuple.c 
b/contrib/pgstattuple/pgstattuple.c
index 7ca1bb24d2..b599b6ca21 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -89,7 +89,7 @@ static Datum
 build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 {
 #define NCOLUMNS       9
-#define NCHARS         32
+#define NCHARS         314
 
        HeapTuple       tuple;
        char       *values[NCOLUMNS];
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 900fa74e85..f0dfef5a86 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -3337,10 +3337,11 @@ void
 ExplainPropertyFloat(const char *qlabel, double value, int ndigits,
                                         ExplainState *es)
 {
-       char            buf[256];
+       char       *buf;
 
-       snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
+       buf = psprintf("%.*f", ndigits, value);
        ExplainProperty(qlabel, buf, true, es);
+       pfree(buf);
 }
 
 /*
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 834a10485f..07e5e78caa 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -86,7 +86,7 @@ calculate_database_size(Oid dbOid)
        DIR                *dirdesc;
        struct dirent *direntry;
        char            dirpath[MAXPGPATH];
-       char            pathname[MAXPGPATH + 12 + 
sizeof(TABLESPACE_VERSION_DIRECTORY)];
+       char            pathname[MAXPGPATH + 21 + 
sizeof(TABLESPACE_VERSION_DIRECTORY)];
        AclResult       aclresult;
 
        /*
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index aadb92de66..6522c0816e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -44,10 +44,6 @@ static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
 #define NAN (*(const double *) nan)
 #endif
 
-/* not sure what the following should be, but better to make it 
over-sufficient */
-#define MAXFLOATWIDTH  64
-#define MAXDOUBLEWIDTH 128
-
 /*
  * check to see if a float4/8 val has underflowed or overflowed
  */
@@ -360,18 +356,18 @@ Datum
 float4out(PG_FUNCTION_ARGS)
 {
        float4          num = PG_GETARG_FLOAT4(0);
-       char       *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
+       char       *ascii;
 
        if (isnan(num))
-               PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
+               PG_RETURN_CSTRING(pstrdup("NaN"));
 
        switch (is_infinite(num))
        {
                case 1:
-                       strcpy(ascii, "Infinity");
+                       ascii = pstrdup("Infinity");
                        break;
                case -1:
-                       strcpy(ascii, "-Infinity");
+                       ascii = pstrdup("-Infinity");
                        break;
                default:
                        {
@@ -380,7 +376,7 @@ float4out(PG_FUNCTION_ARGS)
                                if (ndig < 1)
                                        ndig = 1;
 
-                               snprintf(ascii, MAXFLOATWIDTH + 1, "%.*g", 
ndig, num);
+                               ascii = psprintf("%.*g", ndig, num);
                        }
        }
 
@@ -596,18 +592,18 @@ float8out(PG_FUNCTION_ARGS)
 char *
 float8out_internal(double num)
 {
-       char       *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
+       char       *ascii;
 
        if (isnan(num))
-               return strcpy(ascii, "NaN");
+               return pstrdup("NaN");
 
        switch (is_infinite(num))
        {
                case 1:
-                       strcpy(ascii, "Infinity");
+                       ascii = pstrdup("Infinity");
                        break;
                case -1:
-                       strcpy(ascii, "-Infinity");
+                       ascii = pstrdup("-Infinity");
                        break;
                default:
                        {
@@ -616,7 +612,7 @@ float8out_internal(double num)
                                if (ndig < 1)
                                        ndig = 1;
 
-                               snprintf(ascii, MAXDOUBLEWIDTH + 1, "%.*g", 
ndig, num);
+                               ascii = psprintf("%.*g", ndig, num);
                        }
        }
 
diff --git a/src/backend/utils/adt/formatting.c 
b/src/backend/utils/adt/formatting.c
index b8bd4caa3e..1a1088711c 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -117,13 +117,6 @@
 #define DCH_MAX_ITEM_SIZ          12   /* max localized day name               
*/
 #define NUM_MAX_ITEM_SIZ               8       /* roman number (RN has 15 
chars)       */
 
-/* ----------
- * More is in float.c
- * ----------
- */
-#define MAXFLOATWIDTH  60
-#define MAXDOUBLEWIDTH 500
-
 
 /* ----------
  * Format parser structs
@@ -3911,9 +3904,7 @@ do_to_timestamp(text *date_txt, text *fmt,
                        tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
                        DateTimeParseError(DTERR_TZDISP_OVERFLOW, date_str, 
"timestamp");
 
-               tz = palloc(7);
-
-               snprintf(tz, 7, "%c%02d:%02d",
+               tz = psprintf("%c%02d:%02d",
                                 tmfc.tzsign > 0 ? '+' : '-', tmfc.tzh, 
tmfc.tzm);
 
                tm->tm_zone = tz;
@@ -4135,7 +4126,7 @@ int_to_roman(int number)
                                num = 0;
        char       *p = NULL,
                           *result,
-                               numstr[5];
+                               numstr[12];
 
        result = (char *) palloc(16);
        *result = '\0';
@@ -5441,8 +5432,7 @@ int4_to_char(PG_FUNCTION_ARGS)
                /* we can do it easily because float8 won't lose any precision 
*/
                float8          val = (float8) value;
 
-               orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
-               snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
+               orgnum = (char *) psprintf("%+.*e", Num.post, val);
 
                /*
                 * Swap a leading positive sign for a space.
@@ -5641,7 +5631,6 @@ float4_to_char(PG_FUNCTION_ARGS)
                numstr = orgnum = int_to_roman((int) rint(value));
        else if (IS_EEEE(&Num))
        {
-               numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
                if (isnan(value) || is_infinite(value))
                {
                        /*
@@ -5655,7 +5644,7 @@ float4_to_char(PG_FUNCTION_ARGS)
                }
                else
                {
-                       snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, 
value);
+                       numstr = orgnum = psprintf("%+.*e", Num.post, value);
 
                        /*
                         * Swap a leading positive sign for a space.
@@ -5679,8 +5668,7 @@ float4_to_char(PG_FUNCTION_ARGS)
                        Num.pre += Num.multi;
                }
 
-               orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
-               snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
+               orgnum = (char *) psprintf("%.0f", fabs(val));
                numstr_pre_len = strlen(orgnum);
 
                /* adjust post digits to fit max float digits */
@@ -5688,7 +5676,7 @@ float4_to_char(PG_FUNCTION_ARGS)
                        Num.post = 0;
                else if (numstr_pre_len + Num.post > FLT_DIG)
                        Num.post = FLT_DIG - numstr_pre_len;
-               snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
+               orgnum = psprintf("%.*f", Num.post, val);
 
                if (*orgnum == '-')
                {                                               /* < 0 */
@@ -5747,7 +5735,6 @@ float8_to_char(PG_FUNCTION_ARGS)
                numstr = orgnum = int_to_roman((int) rint(value));
        else if (IS_EEEE(&Num))
        {
-               numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
                if (isnan(value) || is_infinite(value))
                {
                        /*
@@ -5761,7 +5748,7 @@ float8_to_char(PG_FUNCTION_ARGS)
                }
                else
                {
-                       snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, 
value);
+                       numstr = orgnum = (char *) psprintf("%+.*e", Num.post, 
value);
 
                        /*
                         * Swap a leading positive sign for a space.
@@ -5784,15 +5771,15 @@ float8_to_char(PG_FUNCTION_ARGS)
                        val = value * multi;
                        Num.pre += Num.multi;
                }
-               orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
-               numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", 
fabs(val));
+               orgnum = psprintf("%.0f", fabs(val));
+               numstr_pre_len = strlen(orgnum);
 
                /* adjust post digits to fit max double digits */
                if (numstr_pre_len >= DBL_DIG)
                        Num.post = 0;
                else if (numstr_pre_len + Num.post > DBL_DIG)
                        Num.post = DBL_DIG - numstr_pre_len;
-               snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
+               orgnum = psprintf("%.*f", Num.post, val);
 
                if (*orgnum == '-')
                {                                               /* < 0 */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1db7845d5a..b1932e5fd6 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10527,7 +10527,7 @@ check_cluster_name(char **newval, void **extra, 
GucSource source)
 static const char *
 show_unix_socket_permissions(void)
 {
-       static char buf[8];
+       static char buf[12];
 
        snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
        return buf;
@@ -10536,7 +10536,7 @@ show_unix_socket_permissions(void)
 static const char *
 show_log_file_mode(void)
 {
-       static char buf[8];
+       static char buf[12];
 
        snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
        return buf;
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 2efd3b75b1..c0ea7df3aa 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1009,12 +1009,12 @@ static char *
 pretty_wal_size(int segment_count)
 {
        int                     sz = wal_segment_size_mb * segment_count;
-       char       *result = pg_malloc(11);
+       char       *result = pg_malloc(14);
 
        if ((sz % 1024) == 0)
-               snprintf(result, 11, "%dGB", sz / 1024);
+               snprintf(result, 14, "%dGB", sz / 1024);
        else
-               snprintf(result, 11, "%dMB", sz);
+               snprintf(result, 14, "%dMB", sz);
 
        return result;
 }
diff --git a/src/bin/pg_dump/pg_backup_archiver.c 
b/src/bin/pg_dump/pg_backup_archiver.c
index fc233a608f..83c976eaf7 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -1532,7 +1532,7 @@ SetOutput(ArchiveHandle *AH, const char *filename, int 
compression)
 #ifdef HAVE_LIBZ
        if (compression != 0)
        {
-               char            fmode[10];
+               char            fmode[14];
 
                /* Don't use PG_BINARY_x since this is zlib */
                sprintf(fmode, "wb%d", compression);
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index ef9f7145b1..007be1298f 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -335,7 +335,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
        TAR_MEMBER *tm;
 
 #ifdef HAVE_LIBZ
-       char            fmode[10];
+       char            fmode[14];
 #endif
 
        if (mode == 'r')
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index d4209421f5..18ced8a2b2 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -3601,7 +3601,7 @@ parseQuery(Command *cmd)
        p = sql;
        while ((p = strchr(p, ':')) != NULL)
        {
-               char            var[12];
+               char            var[13];
                char       *name;
                int                     eaten;
 
@@ -5443,7 +5443,7 @@ threadRun(void *arg)
                                                        sqlat,
                                                        lag,
                                                        stdev;
-                               char            tbuf[64];
+                               char            tbuf[315];
 
                                /*
                                 * Add up the statistics of all threads.
diff --git a/src/include/postmaster/bgworker.h 
b/src/include/postmaster/bgworker.h
index 0c04529f47..a8753df8d1 100644
--- a/src/include/postmaster/bgworker.h
+++ b/src/include/postmaster/bgworker.h
@@ -82,7 +82,7 @@ typedef enum
 
 #define BGW_DEFAULT_RESTART_INTERVAL   60
 #define BGW_NEVER_RESTART                              -1
-#define BGW_MAXLEN                                             64
+#define BGW_MAXLEN                                             96
 #define BGW_EXTRALEN                                   128
 
 typedef struct BackgroundWorker
diff --git a/src/interfaces/libpq/fe-secure-openssl.c 
b/src/interfaces/libpq/fe-secure-openssl.c
index cade4e157c..127122563c 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -1436,7 +1436,7 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
 
        if (strcmp(attribute_name, "key_bits") == 0)
        {
-               static char sslbits_str[10];
+               static char sslbits_str[12];
                int                     sslbits;
 
                SSL_get_cipher_bits(conn->ssl, &sslbits);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 5df4dfdf55..a3d9a8759f 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1459,7 +1459,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid,
                Datum           prosrcdatum;
                bool            isnull;
                char       *proc_source;
-               char            buf[32];
+               char            buf[48];
                Tcl_Interp *interp;
                int                     i;
                int                     tcl_rc;
-- 
2.16.2

Reply via email to