Fix etl::mem_cast cross-size copy constructor and assignment (#1488)

The templated cross-size copy constructor and assignment operator were
broken in two ways:

- They accessed other.buffer / rhs.buffer, which is private in a
  different mem_cast instantiation, so the cross-size overloads failed
  to compile whenever they were actually instantiated.
- They copied Size_ (the destination size) bytes from a source buffer
  that is only Other_Size bytes large, reading past the end of the
  source when the destination was larger.

Use the public data() accessor and copy Other_Size bytes. The existing
static_assert(Size >= Other_Size) guarantees the destination is big
enough.

Add test_mem_cast_copy_and_assign_from_smaller regression test.

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Roland Reichwein 2026-07-07 18:06:05 +02:00 committed by GitHub
parent 165674cb23
commit c52b2ac7b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 20 additions and 2 deletions

View File

@ -115,7 +115,7 @@ namespace etl
{
ETL_STATIC_ASSERT(Size >= Other_Size, "Other size is too large");
memcpy(buffer, other.buffer, Size_);
memcpy(buffer, other.data(), Other_Size);
}
//***********************************
@ -126,7 +126,7 @@ namespace etl
{
ETL_STATIC_ASSERT(Size >= Other_Size, "RHS size is too large");
memcpy(buffer, rhs.buffer, Size_);
memcpy(buffer, rhs.data(), Other_Size);
return *this;
}

View File

@ -152,6 +152,24 @@ namespace
CHECK_EQUAL(3, memCast.ref<Data>().a[2]);
}
//*************************************************************************
// Cross-size copy/assignment must copy only the source's bytes and must
// not read past the end of the (smaller) source buffer.
TEST(test_mem_cast_copy_and_assign_from_smaller)
{
etl::mem_cast<sizeof(uint32_t), alignof(uint32_t)> smaller;
smaller.assign<uint32_t>(0x12345678UL);
// Cross-size copy construct (destination larger than source).
etl::mem_cast<sizeof(uint32_t) * 2U, alignof(uint32_t)> larger_copy(smaller);
CHECK_EQUAL(0x12345678UL, larger_copy.ref<uint32_t>());
// Cross-size assignment (destination larger than source).
etl::mem_cast<sizeof(uint32_t) * 2U, alignof(uint32_t)> larger_assign;
larger_assign = smaller;
CHECK_EQUAL(0x12345678UL, larger_assign.ref<uint32_t>());
}
//*************************************************************************
TEST(test_mem_cast_assign_type_at_dynamic_offset)
{