diff --git a/inkcpp/array.h b/inkcpp/array.h index 5d02dac2..c93db1f4 100644 --- a/inkcpp/array.h +++ b/inkcpp/array.h @@ -35,6 +35,7 @@ class managed_array : public snapshot_interface if constexpr (dynamic) { if constexpr (simple) { _dynamic_data = reinterpret_cast(new char[sizeof(T) * initialCapacity]); + inkAssert(( ::size_t ) _dynamic_data % alignof(T) == 0); } else { _dynamic_data = new T[initialCapacity]; } @@ -113,6 +114,7 @@ class managed_array : public snapshot_interface inkAssert(_size <= _capacity, "Try to append to a full array!"); // TODO(JBenda): Silent fail? } + inkAssert(_size < _capacity); return data()[_size++]; } @@ -197,8 +199,8 @@ class managed_array : public snapshot_interface private: T* _dynamic_data = nullptr; - size_t _capacity; - size_t _size; + size_t _capacity = 0; + size_t _size = 0; if_t _static_data[dynamic ? 1 : initialCapacity]; }; @@ -273,13 +275,22 @@ void managed_array::extend(size_t capacity) } T* new_data = nullptr; if constexpr (simple) { + // Warning: Allocating typed data in a char* container is potentially unsafe. We need to be sure + // the alignment is compatible with the destination type... new_data = reinterpret_cast(new char[sizeof(T) * new_capacity]); + inkAssert(( ::size_t ) new_data % alignof(T) == 0); + + // ...and we have to copy the contents byte-by-byte, since client code (_list_handouts) + // type-puns between two classes with different vtbls here. Copying these elementwise would + // change the stored C++ type. + memcpy(new_data, _dynamic_data, sizeof(T) * _capacity); } else { + // Allocate and copy typed data normally new_data = new T[new_capacity]; - } - for (size_t i = 0; i < _capacity; ++i) { - new_data[i] = _dynamic_data[i]; + for (size_t i = 0; i < _capacity; ++i) { + new_data[i] = _dynamic_data[i]; + } } if constexpr (simple) { diff --git a/inkcpp/list_table.cpp b/inkcpp/list_table.cpp index d4236983..b4c2d143 100644 --- a/inkcpp/list_table.cpp +++ b/inkcpp/list_table.cpp @@ -825,6 +825,7 @@ list_table::list list_table::redefine(list lh, list rh) list_interface* list_table::handout_list(list l) { static_assert(sizeof(list_interface) == sizeof(list_impl)); + static_assert(alignof(list_interface) == alignof(list_impl)); auto& res = _list_handouts.push(); new (&res) list_impl(*this, l.lid); return &res;