/src/FreeRDP/winpr/libwinpr/crt/alignment.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * WinPR: Windows Portable Runtime |
3 | | * Data Alignment |
4 | | * |
5 | | * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
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 | 0 | #define WINPR_ALIGNED_MEM_SIGNATURE 0x0BA0BAB |
33 | | |
34 | | #define WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(_memptr) \ |
35 | 0 | (WINPR_ALIGNED_MEM*)(((size_t)(((BYTE*)_memptr) - sizeof(WINPR_ALIGNED_MEM)))) |
36 | | |
37 | | #include <stdlib.h> |
38 | | |
39 | | #if defined(__APPLE__) |
40 | | #include <malloc/malloc.h> |
41 | | #elif defined(__FreeBSD__) || defined(__OpenBSD__) |
42 | | #include <stdlib.h> |
43 | | #else |
44 | | #include <malloc.h> |
45 | | #endif |
46 | | |
47 | | #include "../log.h" |
48 | | #define TAG WINPR_TAG("crt") |
49 | | |
50 | | struct winpr_aligned_mem |
51 | | { |
52 | | UINT32 sig; |
53 | | size_t size; |
54 | | void* base_addr; |
55 | | }; |
56 | | typedef struct winpr_aligned_mem WINPR_ALIGNED_MEM; |
57 | | |
58 | | void* winpr_aligned_malloc(size_t size, size_t alignment) |
59 | 0 | { |
60 | 0 | return winpr_aligned_offset_malloc(size, alignment, 0); |
61 | 0 | } |
62 | | |
63 | | void* winpr_aligned_calloc(size_t count, size_t size, size_t alignment) |
64 | 0 | { |
65 | 0 | return winpr_aligned_recalloc(NULL, count, size, alignment); |
66 | 0 | } |
67 | | |
68 | | void* winpr_aligned_realloc(void* memblock, size_t size, size_t alignment) |
69 | 0 | { |
70 | 0 | return winpr_aligned_offset_realloc(memblock, size, alignment, 0); |
71 | 0 | } |
72 | | |
73 | | void* winpr_aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment) |
74 | 0 | { |
75 | 0 | return winpr_aligned_offset_recalloc(memblock, num, size, alignment, 0); |
76 | 0 | } |
77 | | |
78 | | void* winpr_aligned_offset_malloc(size_t size, size_t alignment, size_t offset) |
79 | 0 | { |
80 | 0 | size_t header, alignsize; |
81 | 0 | uintptr_t basesize; |
82 | 0 | void* base; |
83 | 0 | void* memblock; |
84 | 0 | WINPR_ALIGNED_MEM* pMem; |
85 | | |
86 | | /* alignment must be a power of 2 */ |
87 | 0 | if (alignment % 2 == 1) |
88 | 0 | return NULL; |
89 | | |
90 | | /* offset must be less than size */ |
91 | 0 | if (offset >= size) |
92 | 0 | return NULL; |
93 | | |
94 | | /* minimum alignment is pointer size */ |
95 | 0 | if (alignment < sizeof(void*)) |
96 | 0 | alignment = sizeof(void*); |
97 | |
|
98 | 0 | if (alignment > SIZE_MAX - sizeof(WINPR_ALIGNED_MEM)) |
99 | 0 | return NULL; |
100 | | |
101 | 0 | header = sizeof(WINPR_ALIGNED_MEM) + alignment; |
102 | |
|
103 | 0 | if (size > SIZE_MAX - header) |
104 | 0 | return NULL; |
105 | | |
106 | 0 | alignsize = size + header; |
107 | | /* malloc size + alignment to make sure we can align afterwards */ |
108 | | #if defined(_ISOC11_SOURCE) |
109 | | base = aligned_alloc(alignment, alignsize); |
110 | | #elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 |
111 | 0 | if (posix_memalign(&base, alignment, alignsize) != 0) |
112 | 0 | return NULL; |
113 | | #else |
114 | | base = malloc(alignsize); |
115 | | #endif |
116 | 0 | if (!base) |
117 | 0 | return NULL; |
118 | | |
119 | 0 | basesize = (uintptr_t)base; |
120 | |
|
121 | 0 | if ((offset > UINTPTR_MAX) || (header > UINTPTR_MAX - offset) || |
122 | 0 | (basesize > UINTPTR_MAX - header - offset)) |
123 | 0 | { |
124 | 0 | free(base); |
125 | 0 | return NULL; |
126 | 0 | } |
127 | | |
128 | 0 | memblock = (void*)(((basesize + header + offset) & ~(alignment - 1)) - offset); |
129 | 0 | pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); |
130 | 0 | pMem->sig = WINPR_ALIGNED_MEM_SIGNATURE; |
131 | 0 | pMem->base_addr = base; |
132 | 0 | pMem->size = size; |
133 | 0 | return memblock; |
134 | 0 | } |
135 | | |
136 | | void* winpr_aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset) |
137 | 0 | { |
138 | 0 | size_t copySize; |
139 | 0 | void* newMemblock; |
140 | 0 | WINPR_ALIGNED_MEM* pMem; |
141 | 0 | WINPR_ALIGNED_MEM* pNewMem; |
142 | |
|
143 | 0 | if (!memblock) |
144 | 0 | return winpr_aligned_offset_malloc(size, alignment, offset); |
145 | | |
146 | 0 | pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); |
147 | |
|
148 | 0 | if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) |
149 | 0 | { |
150 | 0 | WLog_ERR(TAG, |
151 | 0 | "_aligned_offset_realloc: memory block was not allocated by _aligned_malloc!"); |
152 | 0 | return NULL; |
153 | 0 | } |
154 | | |
155 | 0 | if (size == 0) |
156 | 0 | { |
157 | 0 | winpr_aligned_free(memblock); |
158 | 0 | return NULL; |
159 | 0 | } |
160 | | |
161 | 0 | newMemblock = winpr_aligned_offset_malloc(size, alignment, offset); |
162 | |
|
163 | 0 | if (!newMemblock) |
164 | 0 | return NULL; |
165 | | |
166 | 0 | pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); |
167 | 0 | copySize = (pNewMem->size < pMem->size) ? pNewMem->size : pMem->size; |
168 | 0 | CopyMemory(newMemblock, memblock, copySize); |
169 | 0 | winpr_aligned_free(memblock); |
170 | 0 | return newMemblock; |
171 | 0 | } |
172 | | |
173 | | static INLINE size_t cMIN(size_t a, size_t b) |
174 | 0 | { |
175 | 0 | if (a > b) |
176 | 0 | return b; |
177 | 0 | return a; |
178 | 0 | } |
179 | | |
180 | | void* winpr_aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment, |
181 | | size_t offset) |
182 | 0 | { |
183 | 0 | char* newMemblock = NULL; |
184 | 0 | WINPR_ALIGNED_MEM* pMem = NULL; |
185 | 0 | WINPR_ALIGNED_MEM* pNewMem = NULL; |
186 | |
|
187 | 0 | if (!memblock) |
188 | 0 | { |
189 | 0 | newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset); |
190 | |
|
191 | 0 | if (newMemblock) |
192 | 0 | { |
193 | 0 | pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); |
194 | 0 | ZeroMemory(newMemblock, pNewMem->size); |
195 | 0 | } |
196 | |
|
197 | 0 | return newMemblock; |
198 | 0 | } |
199 | | |
200 | 0 | pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); |
201 | |
|
202 | 0 | if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) |
203 | 0 | { |
204 | 0 | WLog_ERR(TAG, |
205 | 0 | "_aligned_offset_recalloc: memory block was not allocated by _aligned_malloc!"); |
206 | 0 | goto fail; |
207 | 0 | } |
208 | | |
209 | 0 | if ((num == 0) || (size == 0)) |
210 | 0 | goto fail; |
211 | | |
212 | 0 | if (pMem->size > (1ull * num * size) + alignment) |
213 | 0 | return memblock; |
214 | | |
215 | 0 | newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset); |
216 | |
|
217 | 0 | if (!newMemblock) |
218 | 0 | goto fail; |
219 | | |
220 | 0 | pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); |
221 | 0 | { |
222 | 0 | const size_t csize = cMIN(pMem->size, pNewMem->size); |
223 | 0 | memcpy(newMemblock, memblock, csize); |
224 | 0 | ZeroMemory(newMemblock + csize, pNewMem->size - csize); |
225 | 0 | } |
226 | 0 | fail: |
227 | 0 | winpr_aligned_free(memblock); |
228 | 0 | return newMemblock; |
229 | 0 | } |
230 | | |
231 | | size_t winpr_aligned_msize(void* memblock, size_t alignment, size_t offset) |
232 | 0 | { |
233 | 0 | WINPR_ALIGNED_MEM* pMem; |
234 | |
|
235 | 0 | if (!memblock) |
236 | 0 | return 0; |
237 | | |
238 | 0 | pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); |
239 | |
|
240 | 0 | if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) |
241 | 0 | { |
242 | 0 | WLog_ERR(TAG, "_aligned_msize: memory block was not allocated by _aligned_malloc!"); |
243 | 0 | return 0; |
244 | 0 | } |
245 | | |
246 | 0 | return pMem->size; |
247 | 0 | } |
248 | | |
249 | | void winpr_aligned_free(void* memblock) |
250 | 0 | { |
251 | 0 | WINPR_ALIGNED_MEM* pMem; |
252 | |
|
253 | 0 | if (!memblock) |
254 | 0 | return; |
255 | | |
256 | 0 | pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); |
257 | |
|
258 | 0 | if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) |
259 | 0 | { |
260 | 0 | WLog_ERR(TAG, "_aligned_free: memory block was not allocated by _aligned_malloc!"); |
261 | 0 | return; |
262 | 0 | } |
263 | | |
264 | 0 | free(pMem->base_addr); |
265 | 0 | } |
266 | | |
267 | | #endif /* _WIN32 */ |