1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qmalloc.h"
5#include "qplatformdefs.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10/*
11 Define the container allocation functions in a separate file, so that our
12 users can easily override them.
13*/
14
15QT_BEGIN_NAMESPACE
16
17void *qMallocAligned(size_t size, size_t alignment)
18{
19 return qReallocAligned(ptr: nullptr, size, oldsize: 0, alignment);
20}
21
22void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t alignment)
23{
24 // fake an aligned allocation
25 void *actualptr = oldptr ? static_cast<void **>(oldptr)[-1] : nullptr;
26 if (alignment <= sizeof(void *)) {
27 // special, fast case
28 void **newptr = static_cast<void **>(realloc(ptr: actualptr, size: newsize + sizeof(void *)));
29 if (!newptr)
30 return nullptr;
31 if (newptr == actualptr) {
32 // realloc succeeded without reallocating
33 return oldptr;
34 }
35
36 *newptr = newptr;
37 return newptr + 1;
38 }
39
40 // malloc returns pointers aligned at least at sizeof(size_t) boundaries
41 // but usually more (8- or 16-byte boundaries).
42 // So we overallocate by alignment-sizeof(size_t) bytes, so we're guaranteed to find a
43 // somewhere within the first alignment-sizeof(size_t) that is properly aligned.
44
45 // However, we need to store the actual pointer, so we need to allocate actually size +
46 // alignment anyway.
47
48 qptrdiff oldoffset = oldptr ? static_cast<char *>(oldptr) - static_cast<char *>(actualptr) : 0;
49 void *real = realloc(ptr: actualptr, size: newsize + alignment);
50 if (!real)
51 return nullptr;
52
53 quintptr faked = reinterpret_cast<quintptr>(real) + alignment;
54 faked &= ~(alignment - 1);
55 void **faked_ptr = reinterpret_cast<void **>(faked);
56
57 if (oldptr) {
58 qptrdiff newoffset = reinterpret_cast<char *>(faked_ptr) - static_cast<char *>(real);
59 if (oldoffset != newoffset)
60 memmove(dest: faked_ptr, src: static_cast<char *>(real) + oldoffset, n: qMin(a: oldsize, b: newsize));
61 }
62
63 // now save the value of the real pointer at faked-sizeof(void*)
64 // by construction, alignment > sizeof(void*) and is a power of 2, so
65 // faked-sizeof(void*) is properly aligned for a pointer
66 faked_ptr[-1] = real;
67
68 return faked_ptr;
69}
70
71void qFreeAligned(void *ptr)
72{
73 if (!ptr)
74 return;
75 void **ptr2 = static_cast<void **>(ptr);
76 free(ptr: ptr2[-1]);
77}
78
79QT_END_NAMESPACE
80

source code of qtbase/src/corelib/global/qmalloc.cpp