Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recent build break in fmt master with gcc10 #1810

Closed
lgritz opened this issue Aug 10, 2020 · 15 comments
Closed

Recent build break in fmt master with gcc10 #1810

lgritz opened this issue Aug 10, 2020 · 15 comments

Comments

@lgritz
Copy link

lgritz commented Aug 10, 2020

Recent change in master, commit with SHA 2082912 ("Optimize count_digits") breaks the build on my project with -Wall, but the immediately preceding commit, SHA 8d9ab96 ("Cut a few cycles from count_digits") succeeds.

That doesn't guarantee the the bug is the contents of that commit per se, but maybe it put all the pieces in place for it to be symptomatic.

I'm 90% sure that it's building cleanly in gcc <= 9 and with clang. So it may just be a new warning in gcc10 it's hitting. I'm not seeing incorrect results, so maybe it's a spurious warning that I should be suppressing? Please advise if you think that's what I should do. But the "out of bounds" nature of the error message is worrying, I don't want to suppress it if it's really a buffer overflow problem.

I'm sorry I don't have a small repro case, it's in the middle of a large software project, but maybe this big block of error messages will ring a bell?

In file included from /usr/include/string.h:494,
                 from /usr/include/c++/10/cstring:42,
                 from ../../src/include/OpenImageIO/string_view.h:11,
                 from ../../src/include/OpenImageIO/benchmark.h:13,
                 from ../../src/libutil/strutil_test.cpp:8:
In function ‘void* memcpy(void*, const void*, size_t)’,
    inlined from ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’ at include/detail/fmt/format.h:911:55,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘void test_to_string()’ at ../../src/include/OpenImageIO/strutil.h:533:34:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: writing 2 bytes into a region of size 0 [-Werror=stringop-overflow=]
   34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from include/detail/fmt/ostream.h:13,
                 from ../../src/include/OpenImageIO/strutil.h:42,
                 from ../../src/include/OpenImageIO/benchmark.h:14,
                 from ../../src/libutil/strutil_test.cpp:8:
include/detail/fmt/format.h: In function ‘void test_to_string()’:
include/detail/fmt/format.h:3464:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In file included from /usr/include/string.h:494,
                 from /usr/include/c++/10/cstring:42,
                 from ../../src/include/OpenImageIO/string_view.h:11,
                 from ../../src/include/OpenImageIO/benchmark.h:13,
                 from ../../src/libutil/strutil_test.cpp:8:
In function ‘void* memcpy(void*, const void*, size_t)’,
    inlined from ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’ at include/detail/fmt/format.h:911:55,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘void test_to_string()’ at ../../src/include/OpenImageIO/strutil.h:533:34:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: writing 2 bytes into a region of size 0 [-Werror=stringop-overflow=]
   34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from include/detail/fmt/ostream.h:13,
                 from ../../src/include/OpenImageIO/strutil.h:42,
                 from ../../src/include/OpenImageIO/benchmark.h:14,
                 from ../../src/libutil/strutil_test.cpp:8:
include/detail/fmt/format.h: In function ‘void test_to_string()’:
include/detail/fmt/format.h:3464:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In file included from /usr/include/string.h:494,
                 from /usr/include/c++/10/cstring:42,
                 from ../../src/include/OpenImageIO/string_view.h:11,
                 from ../../src/include/OpenImageIO/benchmark.h:13,
                 from ../../src/libutil/strutil_test.cpp:8:
In function ‘void* memcpy(void*, const void*, size_t)’,
    inlined from ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’ at include/detail/fmt/format.h:911:55,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::do_trial(size_t, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/strutil.h:533:34,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::run(FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:270:33,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::operator()(OpenImageIO_v2_3::string_view, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:138:12,
    inlined from ‘void test_format()’ at ../../src/libutil/strutil_test.cpp:79:11:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: writing 2 bytes into a region of size 0 [-Werror=stringop-overflow=]
   34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from include/detail/fmt/ostream.h:13,
                 from ../../src/include/OpenImageIO/strutil.h:42,
                 from ../../src/include/OpenImageIO/benchmark.h:14,
                 from ../../src/libutil/strutil_test.cpp:8:
include/detail/fmt/format.h: In function ‘void test_format()’:
include/detail/fmt/format.h:3464:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In function ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::do_trial(size_t, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/strutil.h:533:34,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::run(FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:270:33,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::operator()(OpenImageIO_v2_3::string_view, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:138:12,
    inlined from ‘void test_format()’ at ../../src/libutil/strutil_test.cpp:79:11:
include/detail/fmt/format.h:936:12: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
  936 |     *--out = static_cast<Char>('0' + value);
      |     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/detail/fmt/format.h: In function ‘void test_format()’:
include/detail/fmt/format.h:3464:8: note: at offset -3 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In file included from /usr/include/string.h:494,
                 from /usr/include/c++/10/cstring:42,
                 from ../../src/include/OpenImageIO/string_view.h:11,
                 from ../../src/include/OpenImageIO/benchmark.h:13,
                 from ../../src/libutil/strutil_test.cpp:8:
In function ‘void* memcpy(void*, const void*, size_t)’,
    inlined from ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’ at include/detail/fmt/format.h:911:55,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::do_trial(size_t, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/strutil.h:533:34,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::run(FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:258:39,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::operator()(OpenImageIO_v2_3::string_view, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:138:12,
    inlined from ‘void test_format()’ at ../../src/libutil/strutil_test.cpp:79:11:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: writing 2 bytes into a region of size 0 [-Werror=stringop-overflow=]
   34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from include/detail/fmt/ostream.h:13,
                 from ../../src/include/OpenImageIO/strutil.h:42,
                 from ../../src/include/OpenImageIO/benchmark.h:14,
                 from ../../src/libutil/strutil_test.cpp:8:
include/detail/fmt/format.h: In function ‘void test_format()’:
include/detail/fmt/format.h:3464:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In function ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:1792:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at include/detail/fmt/format.h:3466:62,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::do_trial(size_t, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/strutil.h:533:34,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::run(FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:258:39,
    inlined from ‘double OpenImageIO_v2_3::Benchmarker::operator()(OpenImageIO_v2_3::string_view, FUNC, ARGS&& ...) [with FUNC = test_format()::<lambda()>; ARGS = {}]’ at ../../src/include/OpenImageIO/benchmark.h:138:12,
    inlined from ‘void test_format()’ at ../../src/libutil/strutil_test.cpp:79:11:
include/detail/fmt/format.h:936:12: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
  936 |     *--out = static_cast<Char>('0' + value);
      |     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/detail/fmt/format.h: In function ‘void test_format()’:
include/detail/fmt/format.h:3464:8: note: at offset -3 to object ‘buffer’ with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
cc1plus: all warnings being treated as errors

@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

I don't see anything wrong with the buffer access and wasn't able to repro the issue in godbolt (https://godbolt.org/z/nodo79). What is the value passed to to_string that triggers the warning?

@lgritz
Copy link
Author

lgritz commented Aug 10, 2020

Near as I can tell, it's a call to

to_string(123)

I'll see if I can reproduce it in a simple way that's not in the middle of my software system.

Maybe this just reveals that there's something important I never realized about godbolt, but how does that example know which version of fmt to use?

@lgritz
Copy link
Author

lgritz commented Aug 10, 2020

Ah, I see where fmt comes from. Did not know Compiler Explorer has all those libraries pre-installed. Cool.

On my laptop (OSX) running g++-10, as well as on GH CI, I can easily make this fail:

#include <iostream>
#    define FMT_HEADER_ONLY
#include "fmt/format.h"

int main (int argc, const char* argv[])
{
    std::cout << fmt::to_string(123) << "\n";
}

But it does not on Compiler Explorer. No explanation for you at the moment. The only thing I can think of is... Are you confident that the fmt "trunk" on Compiler Explorer is really the current master?

The -O3 is required for the failure, but as it turns out, the -Wall is not. Here is my command line:

g++-10 -O3  -o testx -I$OpenImageIO_ROOT/include/OpenImageIO/detail testx.cpp

And here is the error I get:

In file included from testx.cpp:3:
In function 'fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]',
    inlined from 'OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]' at /Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:1792:28,
    inlined from 'std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]' at /Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:3466:62,
    inlined from 'int main(int, const char**)' at testx.cpp:7:36:
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:911:55: warning: writing 2 bytes into a region of size 0 [-Wstringop-overflow=]
  911 | inline void copy2(char* dst, const char* src) { memcpy(dst, src, 2); }
      |                                                 ~~~~~~^~~~~~~~~~~~~
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h: In function 'int main(int, const char**)':
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:3464:8: note: at offset -2 to object 'buffer' with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
In function 'fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]',
    inlined from 'OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]' at /Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:1792:28,
    inlined from 'std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]' at /Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:3466:62,
    inlined from 'int main(int, const char**)' at testx.cpp:7:36:
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:936:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
  936 |     *--out = static_cast<Char>('0' + value);
      |     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h: In function 'int main(int, const char**)':
/Users/lg/code/oiio/oiio.lg/dist/macosx/include/OpenImageIO/detail/fmt/format.h:3464:8: note: at offset -3 to object 'buffer' with size 11 declared here
 3464 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~

Any suggestions about the next experiment I can run to help track this down?

@OnurKader
Copy link

I did a clean build of master by cloning it to a new directory and I got similar warnings during the compilation of
the printf-test (FMT_PEDANTIC was OFF)

$ cmake ..
-- CMake version: 3.17.2
-- The CXX compiler identification is GNU 10.2.1
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Version: 7.0.3
-- Build type: Release
-- CXX_STANDARD: 11
-- Performing Test has_std_11_flag
-- Performing Test has_std_11_flag - Success
-- Performing Test has_std_0x_flag
-- Performing Test has_std_0x_flag - Success
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS
-- Performing Test SUPPORTS_USER_DEFINED_LITERALS - Success
-- Performing Test FMT_HAS_VARIANT
-- Performing Test FMT_HAS_VARIANT - Success
-- Required features: cxx_variadic_templates
-- Looking for strtod_l
-- Looking for strtod_l - found
-- Looking for C++ include pthread.h
-- Looking for C++ include pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Performing Test HAVE_FNO_DELETE_NULL_POINTER_CHECKS
-- Performing Test HAVE_FNO_DELETE_NULL_POINTER_CHECKS - Success
-- FMT_PEDANTIC: OFF
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/fmt/build
[ 96%] Linking CXX executable ../bin/chrono-test
[ 96%] Built target chrono-test
In file included from /tmp/fmt/include/fmt/color.h:11,
                 from /tmp/fmt/test/format-test.cc:27:
In function ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at /tmp/fmt/include/fmt/format.h:1802:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at /tmp/fmt/include/fmt/format.h:3477:62,
    inlined from ‘virtual void FormatTest_ToString_Test::TestBody()’ at /tmp/fmt/test/format-test.cc:1930:3:
/tmp/fmt/include/fmt/format.h:918:55: warning: writing 2 bytes into a region of size 0 [-Wstringop-overflow=]
  918 | inline void copy2(char* dst, const char* src) { memcpy(dst, src, 2); }
      |                                                 ~~~~~~^~~~~~~~~~~~~
/tmp/fmt/include/fmt/format.h: In member function ‘virtual void FormatTest_ToString_Test::TestBody()’:
/tmp/fmt/include/fmt/format.h:3475:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3475 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
[ 98%] Linking CXX executable ../bin/printf-test
[ 98%] Built target printf-test
[100%] Linking CXX executable ../bin/format-test
[100%] Built target format-test

Tests ran successfully

But compiling an FMT_HEADER_ONLY program doesn't produce any warnings

#define FMT_HEADER_ONLY
#include <fmt/format.h>
#include <fmt/ranges.h>

int main()
{
	fmt::print("Hello There!\n{}\n", "General Kenobi!");
	fmt::print("Woah: {}\n", 42);
	const std::string num = fmt::to_string(96);
	fmt::print("Reversed: {}\n", fmt::join(num.crbegin(), num.crend(), ""));

	return 0;
}
$ # Using gcc 10.2.1 20200807, compiled with the following flags
$ g++ -o a a.cpp -std=c++2a -O3 -Wall -Wextra -Werror -Wshadow -Wpedantic -Wconversion -Wstringop-overflow=4 -Wshift-overflow=2 -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wdisabled-optimization -Wno-format-nonliteral

@OnurKader
Copy link

And the following from an FMT_PEDANTIC build

[ 94%] Linking CXX executable ../bin/chrono-test
[ 94%] Built target chrono-test
[ 96%] Linking CXX executable ../bin/compile-test
[ 96%] Built target compile-test
In file included from /tmp/fmt/include/fmt/color.h:11,
                 from /tmp/fmt/test/format-test.cc:27:
In function ‘fmt::v7::detail::format_decimal_result<Char*> fmt::v7::detail::format_decimal(Char*, UInt, int) [with Char = char; UInt = unsigned int]’,
    inlined from ‘OutputIt fmt::v7::detail::write(OutputIt, T) [with Char = char; OutputIt = char*; T = int; typename std::enable_if<((fmt::v7::detail::is_integral<T>::value && (! std::is_same<T, bool>::value)) && (! std::is_same<T, Char>::value)), int>::type <anonymous> = 0]’ at /tmp/fmt/include/fmt/format.h:1802:28,
    inlined from ‘std::string fmt::v7::to_string(T) [with T = int; typename std::enable_if<std::is_integral<_Tp>::value, int>::type <anonymous> = 0]’ at /tmp/fmt/include/fmt/format.h:3477:62,
    inlined from ‘virtual void FormatTest_ToString_Test::TestBody()’ at /tmp/fmt/test/format-test.cc:1930:3:
/tmp/fmt/include/fmt/format.h:918:55: warning: writing 2 bytes into a region of size 0 [-Wstringop-overflow=]
  918 | inline void copy2(char* dst, const char* src) { memcpy(dst, src, 2); }
      |                                                 ~~~~~~^~~~~~~~~~~~~
/tmp/fmt/include/fmt/format.h: In member function ‘virtual void FormatTest_ToString_Test::TestBody()’:
/tmp/fmt/include/fmt/format.h:3475:8: note: at offset -2 to object ‘buffer’ with size 11 declared here
 3475 |   char buffer[max_size > 5 ? max_size : 5];
      |        ^~~~~~
[ 98%] Linking CXX executable ../bin/format-test
[ 98%] Built target format-test
[100%] Linking CXX executable ../bin/printf-test
[100%] Built target printf-test

@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

It's clearly a gcc bug: https://godbolt.org/z/fdE1jo

vitaut added a commit that referenced this issue Aug 10, 2020
@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

Worked around in 6fb7c6f, thanks for reporting.

@vitaut vitaut closed this as completed Aug 10, 2020
@madscientist
Copy link

Is this really a bug in GCC 10? Has anyone reported it to them?

@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

Is this really a bug in GCC 10?

Yes, please see https://godbolt.org/z/fdE1jo. GCC incorrectly assumes that count_digits returns 0.

Has anyone reported it to them?

I haven't, please do if you have time.

@lgritz
Copy link
Author

lgritz commented Aug 10, 2020

Wow. Thanks for tracking this down and the workaround.

@mpolacek
Copy link

Has anyone reported it to them?

I haven't, please do if you have time.

I'm going to take a look at this today. Was there a GCC version in which this problem didn't show up?

@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

Was there a GCC version in which this problem didn't show up?

Yes, GCC 9.3: https://godbolt.org/z/Wvch7T

@mpolacek
Copy link

Great, that should help me, thanks.

@mpolacek
Copy link

OK, so this is https://gcc.gnu.org/PR95353 which has already been fixed in GCC mainline. I'm not sure if the fix will be backported to GCC 10.

@vitaut
Copy link
Contributor

vitaut commented Aug 10, 2020

@mpolacek, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants