https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127666
Bug ID: 127666
Summary: std::from_chars(first, last, long double&) reads past
'last' for "inf"/"nan" (strlen on the unterminated
input)
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: lewis at sophists dot com
Target Milestone: ---
Host: x86_64-pc-linux-gnu
Known to fail: 11.4.0, 14.2.0, 15.2.0, 16.0
For long double, std::from_chars reads beyond the end of its input when the
text is an
infinity or NaN. The result is correct, but the input need not be
NUL-terminated, and
for "inf" in a 3-byte buffer the read runs off the allocation:
#include <charconv>
#include <cstdlib>
#include <cstring>
int main()
{
char* p = static_cast<char*>(std::malloc(3)); // "inf", no NUL
terminator
std::memcpy(p, "inf", 3);
long double v;
auto r = std::from_chars(p, p + 3, v);
std::free(p);
return r.ec == std::errc{} && r.ptr == p + 3 ? 0 : 1;
}
$ g++ -std=c++17 -g -fsanitize=address pr.cpp && ./a.out
ERROR: AddressSanitizer: heap-buffer-overflow ... READ of size 4
#0 strlen
#1 (libstdc++.so)
#2 (libstdc++.so)
#3 main pr.cpp:11
float and double are not affected. Under valgrind memcheck, the same read shows
up as
"Conditional jump or move depends on uninitialised value(s)" in strlen, called
from
std::(anonymous namespace)::pattern via from_chars_strtod<long double>. That is
how we
found it: the bytes after the text in our buffer were uninitialized.
The cause is in src/c++17/floating_from_chars.cc, pattern(), in the
infinity/NaN branch:
buf.assign(first, 0, len);
'first' is a const char*, and basic_string has no assign(const char*,
size_type,
size_type), so this resolves to assign(const basic_string&, size_type,
size_type) with
a temporary string built from 'first' - a strlen that ignores 'last' - of which
only
len characters are then kept. The intended call is presumably:
buf.assign(first, len);
as elsewhere in the same function (buf.assign(first, last)). The line is
unchanged on
master.
(NOTE - report significantly clarified by Claude Opus 5.5).