mirror of
https://github.com/fmtlib/fmt.git
synced 2026-10-29 02:17:28 +08:00
Fix allocation size overflow in detail::allocator
allocator<T>::allocate(n) computed n * sizeof(T) with only an FMT_ASSERT
guarding against overflow, which is a no-op under NDEBUG. On 32-bit targets
a width of 2^30 or more with a 4-byte character type, e.g.
fmt::format(L"{:>{}}", s, 1100000000), wraps the byte count around, and
basic_memory_buffer records a capacity much larger than the block it got,
so padding is written past the end of the allocation.
Make the check unconditional and throw std::bad_alloc, as std::allocator
did before it was replaced in 11.1.0. Move <new> back to format.h since the
header now throws std::bad_alloc.
This commit is contained in:
parent
011e5a911f
commit
6b528261ec
@ -18,7 +18,6 @@ extern "C" void __tsan_release(void*);
|
||||
|
||||
# include <algorithm>
|
||||
# include <cerrno> // errno
|
||||
# include <new> // std::bad_alloc
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE)
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
|
||||
# include <cmath> // std::signbit
|
||||
# include <limits> // std::numeric_limits
|
||||
# include <new> // std::bad_alloc
|
||||
# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)
|
||||
// Workaround for pre gcc 5 libstdc++.
|
||||
# include <memory> // std::allocator_traits
|
||||
@ -905,7 +906,7 @@ template <typename T> struct allocator : private std::decay<void> {
|
||||
using value_type = T;
|
||||
|
||||
FMT_CONSTEXPR20 auto allocate(size_t n) -> T* {
|
||||
FMT_ASSERT(n <= max_value<size_t>() / sizeof(T), "");
|
||||
if (n > max_value<size_t>() / sizeof(T)) FMT_THROW(std::bad_alloc());
|
||||
#if FMT_USE_CONSTEVAL
|
||||
// Use the builtin directly to avoid C++ runtime dependencies at -O0.
|
||||
if (__builtin_is_constant_evaluated()) return new T[n];
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
#include <mutex> // std::mutex
|
||||
#include <new> // std::bad_alloc
|
||||
#include <string> // std::string
|
||||
#include <thread> // std::thread
|
||||
#include <type_traits> // std::is_default_constructible
|
||||
@ -581,6 +582,12 @@ TEST(memory_buffer_test, max_size_allocator_overflow) {
|
||||
EXPECT_THROW(buffer.resize(161), std::exception);
|
||||
}
|
||||
|
||||
TEST(memory_buffer_test, default_allocator_overflow) {
|
||||
// n * sizeof(char32_t) would wrap around to a small nonzero value.
|
||||
size_t n = max_value<size_t>() / sizeof(char32_t) + 2;
|
||||
EXPECT_THROW(fmt::detail::allocator<char32_t>().allocate(n), std::bad_alloc);
|
||||
}
|
||||
|
||||
TEST(memory_buffer_test, back_insert_iterator) {
|
||||
fmt::memory_buffer buf;
|
||||
using iterator = decltype(std::back_inserter(buf));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user