From e701254b02944ecbf228e0c81ef77da86453d260 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 28 Sep 2016 19:03:26 +0100 Subject: [PATCH] Fix String::Data::reserve on big endian platforms, and document String::Data reserve was not ensuring the capacity would be pair, which is needed on big endian machines, as we use its least significant bit to flag short string optimizations. On little endian the bit we use is the 8th most significant (the least significant bit of the last byte), so we were not hitting any problems. Fixes #828 --- src/string.cc | 5 +++++ src/string.hh | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/string.cc b/src/string.cc index edfd4cf6..d7522bd8 100644 --- a/src/string.cc +++ b/src/string.cc @@ -17,6 +17,7 @@ String::Data::Data(const char* data, size_t size, size_t capacity) if (capacity & 1) ++capacity; + kak_assert(capacity < Long::max_capacity); l.ptr = Alloc{}.allocate(capacity+1); l.size = size; l.capacity = capacity; @@ -71,6 +72,10 @@ void String::Data::reserve(size_t new_capacity) if (is_long()) new_capacity = std::max(l.capacity * 2, new_capacity); + if (new_capacity & 1) + ++new_capacity; + + kak_assert(new_capacity < Long::max_capacity); char* new_ptr = Alloc{}.allocate(new_capacity+1); if (copy) { diff --git a/src/string.hh b/src/string.hh index be140888..3fa08a83 100644 --- a/src/string.hh +++ b/src/string.hh @@ -130,12 +130,22 @@ public: static const String ms_empty; static constexpr const char* option_type_name = "str"; + // String data storage using small string optimization. + // + // the LSB of the last byte is used to flag if we are using the small buffer + // or an allocated one. On big endian systems that means the allocated + // capacity must be pair, on little endian systems that means the allocated + // capacity cannot use its most significant byte, so we effectively limit + // capacity to 2^24 on 32bit arch, and 2^60 on 64. union Data { using Alloc = Allocator; struct Long { + static constexpr size_t max_capacity = + (size_t)1 << 8 * (sizeof(size_t) - 1); + char* ptr; size_t size; size_t capacity;