https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116180
Bug ID: 116180 Summary: False positive -Wstringop-overread when calling std::strlen on pointer to static constexpr member std::array containing contents of a non-null terminated string followed by a null terminator Product: gcc Version: 14.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: tanelson at lcmail dot lcsc.edu Target Milestone: --- Created attachment 58797 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58797&action=edit .ii output from g++ -v -save-temps -example.cpp -Wall Some source code to trigger the warning is as follows: #include<array> #include<cstring> using c_string_t = char const *; template<c_string_t Str, int Len> struct null_terminate_static_string { using backing_t = std::array<char, Len+1>; static constexpr backing_t backing = { [](){ backing_t init {}; using size_t = typename backing_t::size_type; for(size_t i = 0; i < Len; ++i){ init[i] = Str[i]; } return init; }() }; static_assert( backing[Len] == '\0' ); static constexpr c_string_t value = &(backing[0]); }; int main(){ static constexpr char non_null_terminated_char_array[] { 'a' }; constexpr auto null_terminated_char_ptr = null_terminate_static_string<non_null_terminated_char_array, 1>::value; static_assert( null_terminated_char_ptr[0] == 'a' && null_terminated_char_ptr[1] == '\0' ); return std::strlen(null_terminated_char_ptr); } https://godbolt.org/z/PojWKh6ax When compiled with -Wall gives : example.cpp:27:116: warning: ‘strlen’ argument missing terminating nul [-Wstringop-overread] 27 | constexpr auto null_terminated_char_ptr = null_terminate_static_string<non_null_terminated_char_array, 1>::value; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ example.cpp:9:36: note: referenced argument declared here 9 | static constexpr backing_t backing = { ___________________________ As you can see the string is null terminated as it passes asserts, additionally you can see the intel assembly on godbolt that null_terminate_static_string<...>::backing is null terminated with a zero section. For the .s generated on my machine I have also: movl $_ZN28null_terminate_static_stringIXadL_ZZ4mainE30non_null_terminated_char_arrayEELi1EE7backingE, %edi call strlen ... _ZN28null_terminate_static_stringIXadL_ZZ4mainE30non_null_terminated_char_arrayEELi1EE7backingE: .byte 97 .zero 1 .text .globl main .type main, @function Where you can see 'a' (97) followed by a size 1 .zero section. ___________________________ -v output follows: Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../configure --enable-languages=c++ --disable-multilib Thread model: posix Supported LTO compression algorithms: zlib gcc version 14.1.0 (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' /usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/cc1plus -E -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE example.cpp -mtune=generic -march=x86-64 -Wall -fpch-preprocess -o a-example.ii ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../x86_64-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../include/c++/14.1.0 /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../include/c++/14.1.0/x86_64-pc-linux-gnu /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../include/c++/14.1.0/backward /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/include /usr/local/include /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/include-fixed/x86_64-linux-gnu /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/include-fixed /usr/include/x86_64-linux-gnu /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' /usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/cc1plus -fpreprocessed a-example.ii -quiet -dumpdir a- -dumpbase example.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -Wall -version -o a-example.s GNU C++17 (GCC) version 14.1.0 (x86_64-pc-linux-gnu) compiled by GNU C version 14.1.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version none GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 9a7dcfae45e2d61f340191eea1397e8a example.cpp: In function ‘int main()’: example.cpp:27:116: warning: ‘strlen’ argument missing terminating nul [-Wstringop-overread] 27 | constexpr auto null_terminated_char_ptr = null_terminate_static_string<non_null_terminated_char_array, 1>::value; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ example.cpp:9:36: note: referenced argument declared here 9 | static constexpr backing_t backing = { | ^~~~~~~ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' as -v --64 -o a-example.o a-example.s GNU assembler version 2.38 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.38 COMPILER_PATH=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/:/usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/:/usr/local/libexec/gcc/x86_64-pc-linux-gnu/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/ LIBRARY_PATH=/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.' /usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/collect2 -plugin /usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/liblto_plugin.so -plugin-opt=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/lto-wrapper -plugin-opt=-fresolution=a.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/crt1.o /lib/x86_64-linux-gnu/crti.o /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/crtbegin.o -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/../../.. a-example.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/lib/gcc/x86_64-pc-linux-gnu/14.1.0/crtend.o /lib/x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'