ByteSlice: Fix persisting ptr to std::moved SSO buffer

The Bug:
1. Construct `byte_slice.portion_` with `epee::span(buffer)` which copies a pointer to the SSO buffer to `byte_slice.portion_`
2. It constructs `byte_slice.storage_` with `std::move(buffer)` (normally this swap pointers, but SSO means a memcpy and clear on the original SSO buffer)
3. `slice.data()` returns a pointer from `slice.portion_` that points to the original SSO cleared buffer, `slice.storage_` has the actual string.
This commit is contained in:
Doyle 2020-05-19 18:45:32 +10:00
parent eed8a4e8a6
commit 438b84690e
2 changed files with 27 additions and 1 deletions

View file

@ -133,10 +133,13 @@ namespace epee
template<typename T> template<typename T>
byte_slice::byte_slice(const adapt_buffer, T&& buffer) byte_slice::byte_slice(const adapt_buffer, T&& buffer)
: storage_(nullptr), portion_(to_byte_span(to_span(buffer))) : storage_(nullptr), portion_(nullptr)
{ {
if (!buffer.empty()) if (!buffer.empty())
{
storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer)); storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer));
portion_ = to_byte_span(to_span(static_cast<adapted_byte_slice<T> *>(storage_.get())->buffer));
}
} }
byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources) byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources)

View file

@ -387,6 +387,29 @@ TEST(ByteSlice, Construction)
EXPECT_FALSE(std::is_copy_assignable<epee::byte_slice>()); EXPECT_FALSE(std::is_copy_assignable<epee::byte_slice>());
} }
TEST(ByteSlice, DataReturnedMatches)
{
for (int i = 64; i > 0; i--)
{
std::string sso_string(i, 'a');
std::string original = sso_string;
epee::byte_slice slice{std::move(sso_string)};
EXPECT_EQ(slice.size(), original.size());
EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
}
for (int i = 64; i > 0; i--)
{
std::vector<uint8_t> sso_vector(i, 'a');
std::vector<uint8_t> original = sso_vector;
epee::byte_slice slice{std::move(sso_vector)};
EXPECT_EQ(slice.size(), original.size());
EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
}
}
TEST(ByteSlice, NoExcept) TEST(ByteSlice, NoExcept)
{ {
EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_slice>()); EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_slice>());