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