fmt
fmt copied to clipboard
GCC 14 optimizer doesn't like std::filesystem::path formatting (Wstringop-overflow)
Starting with 11.0.2, when using GCC 14, particularly with link time optimization but also reproducible in some cases without, it seems that formatting std::filesystem::path (i.e. fmt::to_string(std::filesystem::path {...})
) produces stringop-overflow warnings. While this can be reproduced by just calling fmt::to_string<std::filesystem::path>
in exploring I found that explicitly instantiating two particular templates seems to be enough to trigger it (one or the other is not enough). Using O3 optimizations seems to be required for this to trigger.
https://godbolt.org/z/Gsvoqz71e
I've traced the change causing this to commit f29a7e7970349eec2c76f3c0eda3d5accdd3aa6b. Specifically just the removal of the copy overload there. Reverting that overload removal is one possible workaround.
Despite the functions that are instantiated there, the actual function in question seems to be for_each_codepoint
. Increasing the size of buf by up to 8 characters eliminates the warnings. I've also had success in getting rid of them by storing the start and end pointers for the string instead and removing the if (s.size() >= block_size)
check to simplify the flow (might have needed an assume somewhere in there too). Ultimately this feels like a false positive to me, and I can report to GCC if agreed.
I've tried various combinations of [[assume()]] without changing the code structure with no avail, so GCC seems particularly stubborn about this one.
In file included from /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:41,
from /opt/compiler-explorer/libs/fmt/trunk/include/fmt/std.h:11,
from <source>:1:
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 8 bytes into a region of size 7 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 16 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 16 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 17 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [1, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 17 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 18 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [2, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 18 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 19 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [3, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 19 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 20 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [4, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 20 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 21 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [5, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 21 into destination object 'buf' of size 7
In function 'constexpr OutputIt fmt::v11::detail::copy(InputIt, InputIt, OutputIt) [with T = char; InputIt = const char*; OutputIt = char*; typename std::enable_if<(! is_back_insert_iterator<OutputIt>::value), int>::type <anonymous> = 0]',
inlined from 'constexpr void fmt::v11::detail::for_each_codepoint(fmt::v11::string_view, F) [with F = find_escape(const char*, const char*)::<lambda(uint32_t, fmt::v11::string_view)>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:678:15,
inlined from 'fmt::v11::detail::find_escape_result<char> fmt::v11::detail::find_escape(const char*, const char*)' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1849:21,
inlined from 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]' at /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1941:30:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1220:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
1220 | while (begin != end) *out++ = static_cast<T>(*begin++);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h: In function 'OutputIt fmt::v11::detail::write_escaped_string(OutputIt, fmt::v11::basic_string_view<Char>) [with Char = char; OutputIt = fmt::v11::basic_appender<char>]':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 22 into destination object 'buf' of size 7
677 | char buf[2 * block_size - 1] = {};
| ^~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset [6, 7] into destination object 'buf' of size 7
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:677:10: note: at offset 22 into destination object 'buf' of size 7