[llvm-branch-commits] [libcxx] release/23.x: [libc++][format] Don't leave the output buffer full after a bulk write (#226791) (PR #226868)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Sep 27 18:55:53 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: llvmbot
<details>
<summary>Changes</summary>
Backport 372dc97670f7b3ce422dc26e5f626b2711426e8d
Requested by: @<!-- -->frederick-vs-ja
---
Full diff: https://github.com/llvm/llvm-project/pull/226868.diff
2 Files Affected:
- (modified) libcxx/include/__format/buffer.h (+12)
- (added) libcxx/test/std/utilities/format/format.functions/bug_154670.pass.cpp (+74)
``````````diff
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index e7454f08f45d5..fbb67b02a6d17 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -250,6 +250,10 @@ class __output_buffer {
__first += __chunk;
__n -= __chunk;
} while (__n);
+
+ // push_back needs a free code unit, which the last chunk may have used.
+ if (__size_ == __capacity_)
+ __prepare_write(0);
}
/// A std::transform wrapper.
@@ -276,6 +280,10 @@ class __output_buffer {
__first += __chunk;
__n -= __chunk;
} while (__n);
+
+ // push_back needs a free code unit, which the last chunk may have used.
+ if (__size_ == __capacity_)
+ __prepare_write(0);
}
/// A \c fill_n wrapper.
@@ -293,6 +301,10 @@ class __output_buffer {
__size_ += __chunk;
__n -= __chunk;
} while (__n);
+
+ // push_back needs a free code unit, which the last chunk may have used.
+ if (__size_ == __capacity_)
+ __prepare_write(0);
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __capacity() const { return __capacity_; }
diff --git a/libcxx/test/std/utilities/format/format.functions/bug_154670.pass.cpp b/libcxx/test/std/utilities/format/format.functions/bug_154670.pass.cpp
new file mode 100644
index 0000000000000..7f36d7d95b6f9
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/bug_154670.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// XFAIL: availability-fp_to_chars-missing
+
+// https://llvm.org/PR154670
+//
+// Formatting into a back_insert_iterator of a string, vector or deque goes
+// through a fixed-size buffer. Tests that the code unit written after an
+// argument or a fill that ends at a multiple of the buffer's size is not
+// written past the end of that buffer.
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <format>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include "make_string.h"
+#include "test_macros.h"
+
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+
+template <class CharT, class Container>
+void test(std::size_t size) {
+ const std::basic_string<CharT> arg(size, CharT('a'));
+ const std::basic_string<CharT> expected = arg + CharT('!');
+
+ { // The argument is copied.
+ Container out;
+ std::format_to(std::back_inserter(out), SV("{}!"), arg);
+ assert(std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+ }
+ if (size != 0) { // The argument's padding is filled.
+ Container out;
+ std::format_to(std::back_inserter(out), SV("{:a<{}}!"), SV(""), size);
+ assert(std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+ }
+ for (std::size_t n : {size, size + 1, size + 2}) {
+ Container out;
+ auto result = std::format_to_n(std::back_inserter(out), n, SV("{}!"), arg);
+ assert(result.size == static_cast<std::ptrdiff_t>(expected.size()));
+ std::size_t written = std::min(n, expected.size());
+ assert(std::equal(out.begin(), out.end(), expected.begin(), expected.begin() + written));
+ }
+}
+
+template <class CharT>
+void test() {
+ for (std::size_t size : {0, 1, 255, 256, 257, 511, 512, 513, 1024}) {
+ test<CharT, std::basic_string<CharT>>(size);
+ test<CharT, std::vector<CharT>>(size);
+ test<CharT, std::deque<CharT>>(size);
+ }
+}
+
+int main(int, char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/226868
More information about the llvm-branch-commits
mailing list