From 97c8873214ea0f625a646537b869289afd480f10 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Thu, 29 Oct 2020 18:17:00 +0500 Subject: [PATCH] Allocator::max_size support in basic_memory_buffer (#1960) --- include/fmt/format.h | 2 ++ test/format-test.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/fmt/format.h b/include/fmt/format.h index 6b03e857..5d90f443 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -742,9 +742,11 @@ void basic_memory_buffer::grow(size_t size) { #ifdef FMT_FUZZ if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); #endif + const size_t max_size = std::allocator_traits::max_size(alloc_); size_t old_capacity = this->capacity(); size_t new_capacity = old_capacity + old_capacity / 2; if (size > new_capacity) new_capacity = size; + else if (new_capacity > max_size) new_capacity = (std::max)(size, max_size); T* old_data = this->data(); T* new_data = std::allocator_traits::allocate(alloc_, new_capacity); diff --git a/test/format-test.cc b/test/format-test.cc index 128b57a2..4d8f90ea 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -354,6 +354,53 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) { EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size)); } +template +class allocator_max_size: public Allocator { + public: + using typename Allocator::value_type; + size_t max_size() const FMT_NOEXCEPT { + return MaxSize; + } + value_type* allocate(size_t n) { + if (n > max_size()) { + throw std::length_error("size > max_size"); + } + return std::allocator_traits::allocate( + *static_cast(this), n); + } + void deallocate(value_type* p, size_t n) { + std::allocator_traits::deallocate( + *static_cast(this), p, n); + } +}; + +TEST(MemoryBufferTest, AllocatorMaxSize) { + // 160 = 128 + 32 + using TestAllocator = allocator_max_size, 160>; + basic_memory_buffer buffer; + buffer.resize(128); + bool throws_on_resize = false; + try { + // new_capacity = 128 + 128/2 = 192 > 160 + buffer.resize(160); + } catch (const std::exception &) { + throws_on_resize = true; + } + EXPECT_FALSE(throws_on_resize); +} + +TEST(MemoryBufferTest, AllocatorMaxSizeOverflow) { + using TestAllocator = allocator_max_size, 160>; + basic_memory_buffer buffer; + bool throws_on_resize = false; + try { + buffer.resize(161); + } catch (const std::exception &) { + throws_on_resize = true; + } + EXPECT_TRUE(throws_on_resize); +} + TEST(UtilTest, UTF8ToUTF16) { fmt::detail::utf8_to_utf16 u("лошадка"); EXPECT_EQ(L"\x043B\x043E\x0448\x0430\x0434\x043A\x0430", u.str());