fix heap overflow in fmt::ostream with buffer_size = 0 (#5011)

output_file(path, buffer_size = 0) allocated a zero-size buffer, but
ostream::grow can only make room by flushing, so a zero capacity is never
increased. push_back then writes past the allocation and leaves size()
above capacity(), after which append computes capacity_ - size_ as
SIZE_MAX and copies the rest of the output out of bounds. If the first
write is an append instead, the count is clamped to 0 and print never
returns.

Allocate at least one byte so a zero buffer size behaves like 1.
This commit is contained in:
aizu-m 2026-11-07 22:44:57 +05:30 committed by GitHub
parent 73b747233e
commit 4daaa87b86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 1 deletions

View File

@ -383,7 +383,9 @@ void ostream::grow(buffer<char>& buf, size_t) {
ostream::ostream(cstring_view path, const detail::ostream_params& params)
: buffer<char>(grow), file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
// grow() can only make room by flushing, so the buffer can't be empty.
size_t size = max_of<size_t>(params.buffer_size, 1);
set(new char[size], size);
}
ostream::ostream(ostream&& other) noexcept

View File

@ -295,6 +295,15 @@ TEST(ostream_test, buffer_size) {
EXPECT_READ(in, "foo");
}
TEST(ostream_test, zero_buffer_size) {
auto test_file = uniq_file_name(__LINE__);
fmt::ostream out = fmt::output_file(test_file, fmt::buffer_size = 0);
out.print("{}{}", 'f', "oo");
out.close();
file in(test_file, file::RDONLY);
EXPECT_READ(in, "foo");
}
TEST(ostream_test, truncate) {
auto test_file = uniq_file_name(__LINE__);
{