diff --git a/docs/changelog.txt b/docs/changelog.txt index 113fc16ba9..735ddddf4e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -61,6 +61,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- Core: attempts to delete a pool-allocated DF object will now throw an exception instead of corrupting the heap ## Documentation diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 88c4a93651..37892391a4 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -24,14 +24,15 @@ distribution. #pragma once +#include #include #include #include +#include #include #include #include #include -#include #include "BitArray.h" #include "Export.h" @@ -572,15 +573,23 @@ namespace df * */ + using df_pool_id_t = size_t; + template concept pooled_object = requires () { { T::pool_id } -> std::convertible_to; }; + template concept copy_assignable = std::assignable_from && std::assignable_from; template void *allocator_fn(void *out, const void *in) { - if (out) + constexpr df_pool_id_t invalid_pool_id = static_cast(-1); + // unerase type + T* _out = out ? reinterpret_cast(out) : nullptr; + const T* _in = in ? reinterpret_cast(in) : nullptr; + + if (_out) { if constexpr (copy_assignable) { - *(T*)out = *(const T*)in; + *_out = *_in; return out; } else @@ -588,13 +597,20 @@ namespace df return nullptr; } } - else if (in) + else if (_in) { + if constexpr (pooled_object) + { + if (_in->pool_id != invalid_pool_id) + { + throw std::runtime_error("Pool-allocated type cannot be deallocated with allocator_fn"); + } + } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" - delete (T*)in; + delete _in; #pragma GCC diagnostic pop - return (T*)in; + return const_cast(in); } else return new T();