You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
typedefunsignedintalignment_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 + alignment - 1;
if (-Py_SIZE(self) >= total_size_needed)
{
// holder_offset should at least point into the variable-sized partassert(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 startsconstsize_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
{
constsize_t base_allocation = sizeof(alignment_marker_t) + holder_size + alignment - 1;
void* const base_storage = PyMem_Malloc(base_allocation);
if (base_storage == 0)
throwstd::bad_alloc();
constuintptr_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 conditionsconstuintptr_t padding = alignment == 1 ? 0 : ( alignment - (x & (alignment - 1)) );
constsize_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;
}
}
The else path allocates (sizeof(alignment_marker_t) + holder_size + alignment – 1) bytes from an underlying allocator (PyMem_Malloc(), and in turn the heap). This memory is to be used to return to the caller a block of holder_size bytes, suitably aligned.
After allocating this many bytes (in memory at base_storage), the code then forms an aligned pointer into that allocated memory block at aligned_offset and returns this memory to the caller (as aligned_storage). The problem is that there are fewer than holder_size bytes available after aligned_storage in the underlying block (at base_storage), as (aligned_offset > (sizeof(alignment_marker_t) + alignment – 1)) (i.e. the original allocation size, minus the size the caller expects to be able to use).
If we look at this code running in a debugger on Windows (32-bit, with Python 3.8), we can see why this is happening:
Noting that alignment_marker_t is a typedef for unsigned int, and so sizeof(alignment_marker_t) is 4, then x = base_storage + sizeof(alignment_marker_t) = 2d89c1c4, and so with alignment = 4, we then have:
and so (padding > (alignment – 1)) and the pointer returned will cause the caller to overrun the size of the buffer which has been allocated by one byte!
The solution would be to write the code as the following:
In the following code in
libs\python\src\object\class.cpp
:The
else
path allocates(sizeof(alignment_marker_t) + holder_size + alignment – 1)
bytes from an underlying allocator (PyMem_Malloc()
, and in turn the heap). This memory is to be used to return to the caller a block ofholder_size
bytes, suitably aligned.After allocating this many bytes (in memory at
base_storage
), the code then forms an aligned pointer into that allocated memory block ataligned_offset
and returns this memory to the caller (asaligned_storage
). The problem is that there are fewer thanholder_size
bytes available afteraligned_storage
in the underlying block (atbase_storage
), as(aligned_offset > (sizeof(alignment_marker_t) + alignment – 1))
(i.e. the original allocation size, minus the size the caller expects to be able to use).If we look at this code running in a debugger on Windows (32-bit, with Python 3.8), we can see why this is happening:
Noting that
alignment_marker_t
is a typedef forunsigned int
, and sosizeof(alignment_marker_t)
is4
, thenx = base_storage + sizeof(alignment_marker_t) = 2d89c1c4
, and so withalignment = 4
, we then have:and so
(padding > (alignment – 1))
and the pointer returned will cause the caller to overrun the size of the buffer which has been allocated by one byte!The solution would be to write the code as the following:
The text was updated successfully, but these errors were encountered: