[Bug c/95755] New: GCC 10.1.0 reports bogus sizes in -Werror=format-truncation= error

jonathan.leffler at gmail dot com gcc-bugzilla@gcc.gnu.org
Fri Jun 19 00:07:31 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95755

            Bug ID: 95755
           Summary: GCC 10.1.0 reports bogus sizes in
                    -Werror=format-truncation= error
           Product: gcc
           Version: 10.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jonathan.leffler at gmail dot com
  Target Milestone: ---

Created attachment 48754
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48754&action=edit
Preprocessed source (also in body of bug report)

GCC 10.1.0 on an RHEL 7 machine gives an incorrect warning about truncated
output via snprintf, claiming a size that is much bigger than is justified.

Compilation error induced by -Werror shows:

gcc-10.1.0-bug-v2.c: In function ‘mz_format’:
gcc-10.1.0-bug-v2.c:60:48: error: ‘%s’ directive output may be truncated
writing up to 4551 bytes into a region of size 513 [-Werror=format-truncation=]
   60 |     snprintf(rcb->mz_url, sizeof(rcb->mz_url), "%s/name/%s/abc1234",
      |                                                ^~~~~~~~~~~~~~~~~~~~
gcc-10.1.0-bug-v2.c:60:5: note: ‘snprintf’ output between 15 and 8837 bytes
into a destination of size 513
   60 |     snprintf(rcb->mz_url, sizeof(rcb->mz_url), "%s/name/%s/abc1234",
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   61 |              rcred->variant.variant02.az_field11,
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   62 |       rcred->variant.variant02.common01);
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

The mz_url member is 513 bytes (that's correct); the format string has 15 bytes
apart from the two %s directives (including the null byte); the field
az_field11 is 129 bytes; the field common01 is 161 bytes; the maximum total
length should be much less than 513 bytes (15 + 128 + 160 = 303), therefore,
and not 8837 bytes, and should not suffer truncation and hence the warning
(error) is bogus.

Version and options:

Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-10.1.0/configure --prefix=/usr/gcc/v10.1.0
CC=/usr/gcc/v9.3.0/bin/gcc CXX=/usr/gcc/v9.3.0/bin/g++
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.1.0 (GCC) 
COLLECT_GCC_OPTIONS='-O3' '-Wall' '-Werror' '-c' '-v' '-save-temps'
'-mtune=generic' '-march=x86-64'
 /work1/gcc/v10.1.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/10.1.0/cc1 -E -quiet
-v -iprefix /work1/gcc/v10.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/10.1.0/
gcc-10.1.0-bug-v2.c -mtune=generic -march=x86-64 -Wall -Werror -O3
-fpch-preprocess -o gcc-10.1.0-bug-v2.i
ignoring nonexistent directory
"/work1/gcc/v10.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../x86_64-pc-linux-gnu/include"
ignoring duplicate directory
"/work1/gcc/v10.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/10.1.0/include"
ignoring duplicate directory
"/work1/gcc/v10.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/10.1.0/include-fixed"
ignoring nonexistent directory
"/work1/gcc/v10.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /work1/gcc/v10.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/10.1.0/include
 /work1/gcc/v10.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/10.1.0/include-fixed
 /usr/local/include
 /work1/gcc/v10.1.0/bin/../lib/gcc/../../include
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-O3' '-Wall' '-Werror' '-c' '-v' '-save-temps'
'-mtune=generic' '-march=x86-64'
 /work1/gcc/v10.1.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/10.1.0/cc1
-fpreprocessed gcc-10.1.0-bug-v2.i -quiet -dumpbase gcc-10.1.0-bug-v2.c
-mtune=generic -march=x86-64 -auxbase gcc-10.1.0-bug-v2 -O3 -Wall -Werror
-version -o gcc-10.1.0-bug-v2.s
GNU C17 (GCC) version 10.1.0 (x86_64-pc-linux-gnu)
        compiled by GNU C version 10.1.0, GMP version 6.2.0, MPFR version
4.0.2, MPC version 1.1.0, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C17 (GCC) version 10.1.0 (x86_64-pc-linux-gnu)
        compiled by GNU C version 10.1.0, GMP version 6.2.0, MPFR version
4.0.2, MPC version 1.1.0, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 86d44affd1f923d461a5269e6fdf7b02

Preprocessed output:

# 1 "gcc-10.1.0-bug-v2.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "gcc-10.1.0-bug-v2.c"



# 1 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h" 1
3 4
# 143 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4

# 143 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4
typedef long int ptrdiff_t;
# 209 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4
typedef long unsigned int size_t;
# 321 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4
typedef int wchar_t;
# 415 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4
typedef struct {
  long long __max_align_ll __attribute__((__aligned__(__alignof__(long
long))));
  long double __max_align_ld __attribute__((__aligned__(__alignof__(long
double))));
# 426 "/work1/gcc/v10.1.0/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include/stddef.h"
3 4
} max_align_t;
# 5 "gcc-10.1.0-bug-v2.c" 2
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 24 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 399 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 400 "/usr/include/features.h" 2 3 4
# 25 "/usr/include/sys/cdefs.h" 2 3 4
# 392 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 393 "/usr/include/sys/cdefs.h" 2 3 4
# 6 "gcc-10.1.0-bug-v2.c" 2



# 8 "gcc-10.1.0-bug-v2.c"
extern int snprintf (char *__restrict __s, size_t __maxlen,
                     const char *__restrict __format, ...)

# 10 "gcc-10.1.0-bug-v2.c" 3 4
                         __attribute__ ((__nothrow__)) 
# 10 "gcc-10.1.0-bug-v2.c"
                                   __attribute__ ((__format__ (__printf__, 3,
4)));

typedef struct am_option
{

    char am_field01[128+1];
    char am_field02[256+1];
    char am_field03[64+1];
    char common01[2048+1];
    char am_field04[2048+1];
} awsc_t;

typedef struct az_option
{
    char az_field11[128+1];

    char az_field12[36+1];

    char az_field13[64+1];

    char az_field14[36+1];

    char *az_field15;
    char common01[160+1];
} azrc_t;

typedef struct unified
{
    int flags;
    union alternatives
    {
        awsc_t variant01;
        azrc_t variant02;
    } variant;
} mz_unity;

typedef struct MZ_CB
{
    char mz_url[512+1];
    mz_unity *mz_creds;
} mz_cb;

extern void mz_format(mz_cb *rcb);

void mz_format(mz_cb *rcb)
{
    mz_unity *ocred = rcb->mz_creds;
    mz_unity ncred = *ocred;
    mz_unity *rcred = &ncred;

    snprintf(rcb->mz_url, sizeof(rcb->mz_url), "%s/name/%s/abc1234",
             rcred->variant.variant02.az_field11,
      rcred->variant.variant02.common01);
}

Source code - contains comments about what happens when fields are omitted
(sometimes, the size increases from 8837 to a larger number when a field is
omitted). The first two comments are superfluous (sorry) but needed to keep
line numbers accurate.  The ncred and rcred variables in the function appear to
be a necessary part of the reproduction.  Changing the elements in struct
am_option changes the size of the overflow reported.

GCC 9.2.0 on the same machine does not report any problem.  Both 9.2.0 and
10.1.0 were compiled on this machine by me - not downloaded from somewhere -
but used the relevant source without any changes.

/* Starting from commit 87db316 */
/* Complains about overwriting 8837 bytes into 513 */

#include <stddef.h>     /* size_t */
#include <sys/cdefs.h>  /* __THROWNL */

/* From <stdio.h> */
extern int snprintf (char *__restrict __s, size_t __maxlen,
                     const char *__restrict __format, ...)
                          __THROWNL __attribute__ ((__format__ (__printf__, 3,
4)));

typedef struct am_option
{
    /* Removing any element reduces the size of the overflow */
    char    am_field01[128+1];
    char    am_field02[256+1];
    char    am_field03[64+1];
    char    common01[2048+1];
    char    am_field04[2048+1];
} awsc_t;

typedef struct az_option
{
    char    az_field11[128+1];
    /* Removing az_field12 changes size from 8837 to 8877 */
    char    az_field12[36+1];
    /* Removing az_field13 changes size from 8837 to 8901 */
    char    az_field13[64+1];
    /* Removing az_field14 changes size from 8837 to 8877 */
    char    az_field14[36+1];
    /* Removing az_field15 changes size from 8837 to 8849 */
    char   *az_field15;
    char    common01[160+1];
} azrc_t;

typedef struct unified
{
    int         flags;
    union alternatives
    {
        awsc_t  variant01;
        azrc_t  variant02;
    } variant;
} mz_unity;

typedef struct MZ_CB
{
    char         mz_url[512+1];
    mz_unity     *mz_creds;
} mz_cb;

extern void mz_format(mz_cb *rcb);

void mz_format(mz_cb *rcb)
{
    mz_unity *ocred = rcb->mz_creds;
    mz_unity  ncred = *ocred;
    mz_unity *rcred = &ncred;

    snprintf(rcb->mz_url, sizeof(rcb->mz_url), "%s/name/%s/abc1234",
             rcred->variant.variant02.az_field11,
             rcred->variant.variant02.common01);
}


More information about the Gcc-bugs mailing list