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