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); }