2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-23 05:42:30 +00:00

Respect alignment of by-value storage.

This commit is contained in:
Stefan Seefeld
2021-04-24 14:19:31 -04:00
parent f5d14ef15e
commit aca3c80c4f
13 changed files with 158 additions and 58 deletions

View File

@@ -5,6 +5,7 @@
#include <boost/python/detail/prefix.hpp>
#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround
#include <boost/cstdint.hpp>
#include <boost/python/object/class.hpp>
#include <boost/python/object/instance.hpp>
@@ -721,28 +722,47 @@ namespace objects
} // namespace objects
void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size)
typedef unsigned int alignment_marker_t;
void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size, std::size_t alignment)
{
assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
objects::instance<>* self = (objects::instance<>*)self_;
int total_size_needed = holder_offset + holder_size;
int total_size_needed = holder_offset + holder_size + alignment - 1;
if (-Py_SIZE(self) >= total_size_needed)
{
// holder_offset should at least point into the variable-sized part
assert(holder_offset >= offsetof(objects::instance<>,storage));
size_t allocated = holder_size + alignment;
void* storage = (char*)self + holder_offset;
void* aligned_storage = ::boost::alignment::align(alignment, holder_size, storage, allocated);
// Record the fact that the storage is occupied, noting where it starts
Py_SET_SIZE(self, holder_offset);
return (char*)self + holder_offset;
const size_t offset = reinterpret_cast<uintptr_t>(aligned_storage) - reinterpret_cast<uintptr_t>(storage) + holder_offset;
Py_SET_SIZE(self, offset);
return (char*)self + offset;
}
else
{
void* const result = PyMem_Malloc(holder_size);
if (result == 0)
const size_t base_allocation = sizeof(alignment_marker_t) + holder_size + alignment - 1;
void* const base_storage = PyMem_Malloc(base_allocation);
if (base_storage == 0)
throw std::bad_alloc();
return result;
const uintptr_t x = reinterpret_cast<uintptr_t>(base_storage) + sizeof(alignment_marker_t);
//this has problems for x -> max(void *)
//const size_t padding = alignment - ((x + sizeof(alignment_marker_t)) % alignment);
//only works for alignments with alignments of powers of 2, but no edge conditions
const uintptr_t padding = alignment == 1 ? 0 : ( alignment - (x & (alignment - 1)) );
const size_t aligned_offset = sizeof(alignment_marker_t) + padding;
void* const aligned_storage = (char *)base_storage + aligned_offset;
BOOST_ASSERT((char *) aligned_storage + holder_size <= (char *)base_storage + base_allocation);
alignment_marker_t* const marker_storage = reinterpret_cast<alignment_marker_t *>((char *)aligned_storage - sizeof(alignment_marker_t));
*marker_storage = static_cast<alignment_marker_t>(padding);
return aligned_storage;
}
}
@@ -752,7 +772,9 @@ void instance_holder::deallocate(PyObject* self_, void* storage) throw()
objects::instance<>* self = (objects::instance<>*)self_;
if (storage != (char*)self + Py_SIZE(self))
{
PyMem_Free(storage);
alignment_marker_t* marker_storage = reinterpret_cast<alignment_marker_t *>((char *)storage - sizeof(alignment_marker_t));
void *malloced_storage = (char *) storage - sizeof(alignment_marker_t) - (*marker_storage);
PyMem_Free(malloced_storage);
}
}