FreeRDP
Loading...
Searching...
No Matches
alignment.c
1
20#include <stdlib.h>
21#include <winpr/config.h>
22
23#include <winpr/crt.h>
24#include <winpr/debug.h>
25
26/* Data Alignment: http://msdn.microsoft.com/en-us/library/fs9stz4e/ */
27
28#if !defined(_WIN32) || (defined(__MINGW32__) && !defined(_UCRT))
29
30#include <stdint.h>
31#include <limits.h>
32
33#define WINPR_ALIGNED_MEM_SIGNATURE 0x0BA0BAB
34
35#define WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(_memptr) \
36 (WINPR_ALIGNED_MEM*)(((size_t)(((BYTE*)(_memptr)) - sizeof(WINPR_ALIGNED_MEM))))
37
38#include <stdlib.h>
39
40#include "../log.h"
41#define TAG WINPR_TAG("crt")
42
43struct winpr_aligned_mem
44{
45 UINT32 sig;
46 size_t size;
47 void* base_addr;
48};
49typedef struct winpr_aligned_mem WINPR_ALIGNED_MEM;
50
51#define get_aligned_mem_block(ptr) get_aligned_mem_block_((ptr), __func__, __FILE__, __LINE__)
52
53WINPR_ATTR_NODISCARD
54static inline WINPR_ALIGNED_MEM* get_aligned_mem_block_(void* memblock, const char* fkt,
55 const char* file, size_t line)
56{
57 if (!memblock)
58 return nullptr;
59
60 WINPR_ALIGNED_MEM* pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
61 if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
62 {
63 const DWORD level = WLOG_ERROR;
64 wLog* log = WLog_Get(TAG);
65 if (WLog_IsLevelActive(log, level))
66 {
67 WLog_PrintTextMessage(log, level, line, file, fkt,
68 "memory block was not allocated by _aligned_malloc!");
69 winpr_log_backtrace_ex(log, WLOG_ERROR, 20);
70 }
71 return nullptr;
72 }
73
74 return pMem;
75}
76
77void* winpr_aligned_malloc(size_t size, size_t alignment)
78{
79 return winpr_aligned_offset_malloc(size, alignment, 0);
80}
81
82void* winpr_aligned_calloc(size_t count, size_t size, size_t alignment)
83{
84 return winpr_aligned_recalloc(nullptr, count, size, alignment);
85}
86
87void* winpr_aligned_realloc(void* memblock, size_t size, size_t alignment)
88{
89 return winpr_aligned_offset_realloc(memblock, size, alignment, 0);
90}
91
92void* winpr_aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment)
93{
94 return winpr_aligned_offset_recalloc(memblock, num, size, alignment, 0);
95}
96
97void* winpr_aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
98{
99 size_t header = 0;
100 size_t alignsize = 0;
101 uintptr_t basesize = 0;
102 void* base = nullptr;
103 void* memblock = nullptr;
104 WINPR_ALIGNED_MEM* pMem = nullptr;
105
106 /* alignment must be a power of 2 */
107 if (alignment % 2 == 1)
108 return nullptr;
109
110 /* offset must be less than size */
111 if (offset >= size)
112 return nullptr;
113
114 /* minimum alignment is pointer size */
115 if (alignment < sizeof(void*))
116 alignment = sizeof(void*);
117
118 if (alignment > SIZE_MAX - sizeof(WINPR_ALIGNED_MEM))
119 return nullptr;
120
121 header = sizeof(WINPR_ALIGNED_MEM) + alignment;
122
123 if (size > SIZE_MAX - header)
124 return nullptr;
125
126 alignsize = size + header;
127 /* malloc size + alignment to make sure we can align afterwards */
128#if defined(_ISOC11_SOURCE)
129 base = aligned_alloc(alignment, alignsize);
130#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)
131 if (posix_memalign(&base, alignment, alignsize) != 0)
132 return nullptr;
133#else
134 base = malloc(alignsize);
135#endif
136 if (!base)
137 return nullptr;
138
139 basesize = (uintptr_t)base;
140
141 if ((offset > UINTPTR_MAX) || (header > UINTPTR_MAX - offset) ||
142 (basesize > UINTPTR_MAX - header - offset))
143 {
144 free(base);
145 return nullptr;
146 }
147
148 memblock = (void*)(((basesize + header + offset) & ~(alignment - 1)) - offset);
149 pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
150 pMem->sig = WINPR_ALIGNED_MEM_SIGNATURE;
151 pMem->base_addr = base;
152 pMem->size = size;
153 return memblock;
154}
155
156void* winpr_aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset)
157{
158 size_t copySize = 0;
159
160 if (!memblock)
161 return winpr_aligned_offset_malloc(size, alignment, offset);
162
163 WINPR_ALIGNED_MEM* pMem = get_aligned_mem_block(memblock);
164 if (!pMem)
165 return nullptr;
166
167 if (size == 0)
168 {
169 winpr_aligned_free(memblock);
170 return nullptr;
171 }
172
173 void* newMemblock = winpr_aligned_offset_malloc(size, alignment, offset);
174 if (!newMemblock)
175 return nullptr;
176
177 WINPR_ALIGNED_MEM* pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
178 copySize = (pNewMem->size < pMem->size) ? pNewMem->size : pMem->size;
179 CopyMemory(newMemblock, memblock, copySize);
180 winpr_aligned_free(memblock);
181 return newMemblock;
182}
183
184WINPR_ATTR_NODISCARD static inline size_t cMIN(size_t a, size_t b)
185{
186 if (a > b)
187 return b;
188 return a;
189}
190
191void* winpr_aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment,
192 size_t offset)
193{
194 char* newMemblock = nullptr;
195 WINPR_ALIGNED_MEM* pNewMem = nullptr;
196
197 if (!memblock)
198 {
199 newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
200
201 if (newMemblock)
202 {
203 pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
204 ZeroMemory(newMemblock, pNewMem->size);
205 }
206
207 return newMemblock;
208 }
209
210 WINPR_ALIGNED_MEM* pMem = get_aligned_mem_block(memblock);
211 if (!pMem)
212 goto fail;
213
214 if ((num == 0) || (size == 0))
215 goto fail;
216
217 if (pMem->size > (1ull * num * size) + alignment)
218 return memblock;
219
220 newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
221
222 if (!newMemblock)
223 goto fail;
224
225 pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
226 {
227 const size_t csize = cMIN(pMem->size, pNewMem->size);
228 memcpy(newMemblock, memblock, csize);
229 ZeroMemory(newMemblock + csize, pNewMem->size - csize);
230 }
231fail:
232 winpr_aligned_free(memblock);
233 return newMemblock;
234}
235
236size_t winpr_aligned_msize(void* memblock, WINPR_ATTR_UNUSED size_t alignment,
237 WINPR_ATTR_UNUSED size_t offset)
238{
239 WINPR_ALIGNED_MEM* pMem = get_aligned_mem_block(memblock);
240
241 if (!pMem)
242 return 0;
243
244 return pMem->size;
245}
246
247void winpr_aligned_free(void* memblock)
248{
249 WINPR_ALIGNED_MEM* pMem = get_aligned_mem_block(memblock);
250
251 if (!pMem)
252 return;
253
254 free(pMem->base_addr);
255}
256
257#endif /* _WIN32 */