From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id EF3473857033; Thu, 29 Jun 2023 23:01:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EF3473857033 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1688079684; bh=OtoFsKrsUsIgpedJ5RAJ92t/yuwkQmQlaeq8NUkdvZI=; h=From:To:Subject:Date:From; b=ElSP8LIX5OCzc4qPxBRwE40j2oAf6SfklbSUPW2Od3HcTXNcru2omT/TIa6yP43gm ctZ+76ixKXxe6L0SJMpchsGvwiebEjXfdjUx8YfubebW0WZet2QIx57kDkA8VU4j7O 977DBnNJ4PLxsf/oA+uMFfCfZJIxzVWkShHDKYoA= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-7511] libstdc++: Fix std::format for pointers [PR110239] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-13 X-Git-Oldrev: ae7cdc8c0f5278e7941f1de7c72ffe9f1fed2775 X-Git-Newrev: 2d40cd2f199e32f185d4b72db2043e91313ab7f2 Message-Id: <20230629230124.EF3473857033@sourceware.org> Date: Thu, 29 Jun 2023 23:01:24 +0000 (GMT) List-Id: https://gcc.gnu.org/g:2d40cd2f199e32f185d4b72db2043e91313ab7f2 commit r13-7511-g2d40cd2f199e32f185d4b72db2043e91313ab7f2 Author: Jonathan Wakely Date: Mon Jun 26 14:46:46 2023 +0100 libstdc++: Fix std::format for pointers [PR110239] The formatter for pointers was casting to uint64_t which sign extends a 32-bit pointer and produces a value that won't fit in the provided buffer. Cast to uintptr_t instead. There was also a bug in the __parse_integer helper when converting a wide string to a narrow string in order to use std::from_chars on it. The function would always try to read 32 characters, even if the format string was shorter than that. Fix that bug, and remove the constexpr implementation of __parse_integer by just using __from_chars_alnum instead of from_chars, because that's usable in constexpr even in C++20. libstdc++-v3/ChangeLog: PR libstdc++/110239 * include/std/format (__format::__parse_integer): Fix buffer overflow for wide chars. (formatter::format): Cast to uintptr_t instead of uint64_t. * testsuite/std/format/string.cc: Test too-large widths. (cherry picked from commit 3bb9f9329c378934541ae4cff9977b7487e97cf0) Diff: --- libstdc++-v3/include/std/format | 33 +++++++++-------------------- libstdc++-v3/testsuite/std/format/string.cc | 5 +++++ 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 96a1e62ccc8..9d5981e4882 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -269,39 +269,26 @@ namespace __format if (__first == __last) __builtin_unreachable(); - // TODO: use this loop unconditionally? - // Most integers used for arg-id, width or precision will be small. - if (is_constant_evaluated()) - { - auto __next = __first; - unsigned short __val = 0; - while (__next != __last && '0' <= *__next && *__next <= '9') - { - __val = (__val * 10) + (*__next - '0'); // TODO check overflow? - ++__next; - } - if (__next == __first) - return {0, nullptr}; - return {__val, __next}; - } - - unsigned short __val = 0; if constexpr (is_same_v<_CharT, char>) { - auto [ptr, ec] = std::from_chars(__first, __last, __val); - if (ec == errc{}) - return {__val, ptr}; - return {0, nullptr}; + const auto __start = __first; + unsigned short __val = 0; + // N.B. std::from_chars is not constexpr in C++20. + if (__detail::__from_chars_alnum(__first, __last, __val, 10) + && __first != __start) [[likely]] + return {__val, __first}; } else { + unsigned short __val = 0; constexpr int __n = 32; char __buf[__n]{}; - for (int __i = 0; __i < __n && __first != __last; ++__i) + for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i) __buf[__i] = __first[__i]; auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n); return {__v, __first + (__ptr - __buf)}; } + return {0, nullptr}; } template @@ -2118,7 +2105,7 @@ namespace __format typename basic_format_context<_Out, _CharT>::iterator format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const { - auto __u = reinterpret_cast<__UINT64_TYPE__>(__v); + auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); char __buf[2 + sizeof(__v) * 2]; auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), __u, 16); diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc index e421028a873..d28135ec260 100644 --- a/libstdc++-v3/testsuite/std/format/string.cc +++ b/libstdc++-v3/testsuite/std/format/string.cc @@ -121,6 +121,11 @@ test_format_spec() // Invalid presentation types for strings. VERIFY( ! is_format_string_for("{:S}", "str") ); VERIFY( ! is_format_string_for("{:d}", "str") ); + + // Maximum integer value supported for widths and precisions is USHRT_MAX. + VERIFY( is_format_string_for("{:65535}", 1) ); + VERIFY( ! is_format_string_for("{:65536}", 1) ); + VERIFY( ! is_format_string_for("{:9999999}", 1) ); } int main()