Skip to content

[libc++] std::format reads past the 0 terminator in char[N] arrays #115935

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

Closed
Fulgen301 opened this issue Nov 12, 2024 · 1 comment · Fixed by #116571
Closed

[libc++] std::format reads past the 0 terminator in char[N] arrays #115935

Fulgen301 opened this issue Nov 12, 2024 · 1 comment · Fixed by #116571
Labels
format C++20 std::format or std::print, and anything related to them libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Comments

@Fulgen301
Copy link

Fulgen301 commented Nov 12, 2024

Reproducer

If one passes a fixed size char - array containing a 0-terminated string to std::format, the entire array minus one character is added to the result, instead of just the part until the null terminator. This not only seemingly violates [format.formatter.spec]/2.2, but also doesn't match the behavior of MS-STL or libstdc++. (And only formatting 49 characters out of a 50 character array seems buggy anyway.)

The issue is reproducible with all versions of libc++ that shipped with clang since <format> was added, including current trunk on godbolt.

@github-actions github-actions bot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 12, 2024
@frederick-vs-ja frederick-vs-ja added the format C++20 std::format or std::print, and anything related to them label Nov 13, 2024
@frederick-vs-ja
Copy link
Contributor

See here:

// Char pointer
template <class _Context, class _Tp>
requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)
consteval __arg_t __determine_arg_t() {
return __arg_t::__const_char_type_ptr;
}
// Char array
template <class _Context, class _Tp>
requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
consteval __arg_t __determine_arg_t() {
return __arg_t::__string_view;
}

Per [format.arg]/6, char arrays should be converted to char pointers first.

CC @mordante

ldionne pushed a commit that referenced this issue May 12, 2025
…arrays in formatting (#116571)

Currently, built-in `char`/`wchar_t` arrays are assumed to be
null-terminated sequence with the terminator being the last element in
formatting. This doesn't conform to [format.arg]/6.9.

> otherwise, if `decay_t<TD>` is `char_type*` or `const char_type*`,
> initializes value with `static_cast<const char_type*>(v)`;

The standard wording specifies that character arrays are decayed to
pointers. When the null terminator is not the last element or there's no
null terminator (the latter case is UB), libc++ currently produces
different results.

Also fixes and hardens `formatter<CharT[N], CharT>::format` in
`<__format/formatter_string.h>`. These specializations are rarely used.

Fixes #115935. Also checks the preconditions in this case, which fixes
#116570.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
format C++20 std::format or std::print, and anything related to them libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
2 participants