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