Fix qReallocAligned for reallocation when alignment > 2*sizeof(void*)

When we call realloc, the alignment of the new block may be different
from the old one. When that happens, we need to memmove the data to the
new position, before we start overwriting things.

Task-number: QTBUG-59804
Change-Id: I27b55fdf514247549455fffd14b07ea78918a3d0
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
bb10
Thiago Macieira 2017-03-29 16:38:54 -07:00
parent c807dc3c12
commit 6a83f9aa98
1 changed files with 8 additions and 3 deletions

View File

@ -40,6 +40,7 @@
#include "qplatformdefs.h"
#include <stdlib.h>
#include <string.h>
/*
Define the container allocation functions in a separate file, so that our
@ -79,8 +80,6 @@ void *qMallocAligned(size_t size, size_t alignment)
void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t alignment)
{
// fake an aligned allocation
Q_UNUSED(oldsize);
void *actualptr = oldptr ? static_cast<void **>(oldptr)[-1] : 0;
if (alignment <= sizeof(void*)) {
// special, fast case
@ -110,9 +109,15 @@ void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t align
quintptr faked = reinterpret_cast<quintptr>(real) + alignment;
faked &= ~(alignment - 1);
void **faked_ptr = reinterpret_cast<void **>(faked);
if (oldptr) {
qptrdiff oldoffset = static_cast<char *>(oldptr) - static_cast<char *>(actualptr);
qptrdiff newoffset = reinterpret_cast<char *>(faked_ptr) - static_cast<char *>(real);
if (oldoffset != newoffset)
memmove(faked_ptr, static_cast<char *>(real) + oldoffset, qMin(oldsize, newsize));
}
// now save the value of the real pointer at faked-sizeof(void*)
// by construction, alignment > sizeof(void*) and is a power of 2, so
// faked-sizeof(void*) is properly aligned for a pointer