xref: /aosp_15_r20/external/deqp/framework/delibs/debase/deMemory.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Base Portability Library
3  * -------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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  * \file
21  * \brief Memory management.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "deMemory.h"
25 #include "deInt32.h"
26 
27 #include <stdio.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #define DE_ALIGNED_MALLOC_POSIX 0
33 #define DE_ALIGNED_MALLOC_WIN32 1
34 #define DE_ALIGNED_MALLOC_GENERIC 2
35 
36 #if (DE_OS == DE_OS_UNIX) || ((DE_OS == DE_OS_ANDROID) && (DE_ANDROID_API >= 21))
37 #define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_POSIX
38 #if defined(__FreeBSD__)
39 #include <stdlib.h>
40 #else
41 #include <malloc.h>
42 #endif
43 #elif (DE_OS == DE_OS_WIN32)
44 #define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_WIN32
45 #include <malloc.h>
46 #else
47 #define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_GENERIC
48 #endif
49 
50 #if defined(DE_VALGRIND_BUILD)
51 #include <valgrind/valgrind.h>
52 #if defined(HAVE_VALGRIND_MEMCHECK_H)
53 #include <valgrind/memcheck.h>
54 #endif
55 #endif
56 
57 DE_BEGIN_EXTERN_C
58 
59 /*--------------------------------------------------------------------*//*!
60  * \brief Allocate a chunk of memory.
61  * \param numBytes    Number of bytes to allocate.
62  * \return Pointer to the allocated memory (or null on failure).
63  *//*--------------------------------------------------------------------*/
deMalloc(size_t numBytes)64 void *deMalloc(size_t numBytes)
65 {
66     void *ptr;
67 
68     DE_ASSERT(numBytes > 0);
69 
70     ptr = malloc((size_t)numBytes);
71 
72 #if defined(DE_DEBUG)
73     /* Trash memory in debug builds (if under Valgrind, don't make it think we're initializing data here). */
74 
75     if (ptr)
76         memset(ptr, 0xcd, numBytes);
77 
78 #if defined(DE_VALGRIND_BUILD) && defined(HAVE_VALGRIND_MEMCHECK_H)
79     if (ptr && RUNNING_ON_VALGRIND)
80     {
81         VALGRIND_MAKE_MEM_UNDEFINED(ptr, numBytes);
82     }
83 #endif
84 #endif
85 
86     return ptr;
87 }
88 
89 /*--------------------------------------------------------------------*//*!
90  * \brief Allocate a chunk of memory and initialize it to zero.
91  * \param numBytes    Number of bytes to allocate.
92  * \return Pointer to the allocated memory (or null on failure).
93  *//*--------------------------------------------------------------------*/
deCalloc(size_t numBytes)94 void *deCalloc(size_t numBytes)
95 {
96     void *ptr = deMalloc(numBytes);
97     if (ptr)
98         deMemset(ptr, 0, numBytes);
99     return ptr;
100 }
101 
102 /*--------------------------------------------------------------------*//*!
103  * \brief Reallocate a chunk of memory.
104  * \param ptr        Pointer to previously allocated memory block
105  * \param numBytes    New size in bytes
106  * \return Pointer to the reallocated (and possibly moved) memory block
107  *//*--------------------------------------------------------------------*/
deRealloc(void * ptr,size_t numBytes)108 void *deRealloc(void *ptr, size_t numBytes)
109 {
110     return realloc(ptr, numBytes);
111 }
112 
113 /*--------------------------------------------------------------------*//*!
114  * \brief Free a chunk of memory.
115  * \param ptr    Pointer to memory to free.
116  *//*--------------------------------------------------------------------*/
deFree(void * ptr)117 void deFree(void *ptr)
118 {
119     free(ptr);
120 }
121 
122 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
123 
124 typedef struct AlignedAllocHeader_s
125 {
126     void *basePtr;
127     size_t numBytes;
128 } AlignedAllocHeader;
129 
getAlignedAllocHeader(void * ptr)130 DE_INLINE AlignedAllocHeader *getAlignedAllocHeader(void *ptr)
131 {
132     const size_t hdrSize    = sizeof(AlignedAllocHeader);
133     const uintptr_t hdrAddr = (uintptr_t)ptr - hdrSize;
134 
135     return (AlignedAllocHeader *)hdrAddr;
136 }
137 
138 #endif
139 
deAlignedMalloc(size_t numBytes,size_t alignBytes)140 void *deAlignedMalloc(size_t numBytes, size_t alignBytes)
141 {
142 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
143     /* posix_memalign() requires that alignment must be 2^N * sizeof(void*) */
144     const size_t ptrAlignedAlign = deAlignSize(alignBytes, sizeof(void *));
145     void *ptr                    = DE_NULL;
146 
147     DE_ASSERT(deIsPowerOfTwoSize(alignBytes) && deIsPowerOfTwoSize(ptrAlignedAlign / sizeof(void *)));
148 
149     if (posix_memalign(&ptr, ptrAlignedAlign, numBytes) == 0)
150     {
151         DE_ASSERT(ptr);
152         return ptr;
153     }
154     else
155     {
156         DE_ASSERT(!ptr);
157         return DE_NULL;
158     }
159 
160 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
161     DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
162 
163     return _aligned_malloc(numBytes, alignBytes);
164 
165 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
166     void *const basePtr = deMalloc(numBytes + alignBytes + sizeof(AlignedAllocHeader));
167 
168     DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
169 
170     if (basePtr)
171     {
172         void *const alignedPtr = deAlignPtr((void *)((uintptr_t)basePtr + sizeof(AlignedAllocHeader)), alignBytes);
173         AlignedAllocHeader *const hdr = getAlignedAllocHeader(alignedPtr);
174 
175         hdr->basePtr  = basePtr;
176         hdr->numBytes = numBytes;
177 
178         return alignedPtr;
179     }
180     else
181         return DE_NULL;
182 #else
183 #error "Invalid DE_ALIGNED_MALLOC"
184 #endif
185 }
186 
deAlignedRealloc(void * ptr,size_t numBytes,size_t alignBytes)187 void *deAlignedRealloc(void *ptr, size_t numBytes, size_t alignBytes)
188 {
189 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
190     return _aligned_realloc(ptr, numBytes, alignBytes);
191 
192 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC) || (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
193     if (ptr)
194     {
195         if (numBytes > 0)
196         {
197 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
198             const size_t oldSize = getAlignedAllocHeader(ptr)->numBytes;
199 #else /* DE_ALIGNED_MALLOC_GENERIC */
200             const size_t oldSize = malloc_usable_size(ptr);
201 #endif
202 
203             DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
204 
205             if (oldSize < numBytes || oldSize > numBytes * 2)
206             {
207                 /* Create a new alloc if original is smaller, or more than twice the requested size */
208                 void *const newPtr = deAlignedMalloc(numBytes, alignBytes);
209 
210                 if (newPtr)
211                 {
212                     const size_t copyBytes = numBytes < oldSize ? numBytes : oldSize;
213 
214                     deMemcpy(newPtr, ptr, copyBytes);
215                     deAlignedFree(ptr);
216 
217                     return newPtr;
218                 }
219                 else
220                     return DE_NULL;
221             }
222             else
223                 return ptr;
224         }
225         else
226         {
227             deAlignedFree(ptr);
228             return DE_NULL;
229         }
230     }
231     else
232         return deAlignedMalloc(numBytes, alignBytes);
233 
234 #else
235 #error "Invalid DE_ALIGNED_MALLOC"
236 #endif
237 }
238 
deAlignedFree(void * ptr)239 void deAlignedFree(void *ptr)
240 {
241 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
242     free(ptr);
243 
244 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
245     _aligned_free(ptr);
246 
247 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
248     if (ptr)
249     {
250         AlignedAllocHeader *const hdr = getAlignedAllocHeader(ptr);
251 
252         deFree(hdr->basePtr);
253     }
254 #else
255 #error "Invalid DE_ALIGNED_MALLOC"
256 #endif
257 }
258 
deStrdup(const char * str)259 char *deStrdup(const char *str)
260 {
261 #if (DE_COMPILER == DE_COMPILER_MSC)
262     return _strdup(str);
263 #elif (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
264     /* For some reason Steve doesn't like stdrup(). */
265     size_t len = strlen(str);
266     char *copy = malloc(len + 1);
267     memcpy(copy, str, len);
268     copy[len] = 0;
269     return copy;
270 #else
271     return strdup(str);
272 #endif
273 }
274 
deMemory_selfTest(void)275 void deMemory_selfTest(void)
276 {
277     static const struct
278     {
279         size_t numBytes;
280         size_t alignment;
281     } s_alignedAllocCases[] = {
282         {1, 1},        {1, 2},         {1, 256},        {1, 4096},        {547389, 1},      {547389, 2},
283         {547389, 256}, {547389, 4096}, {52532, 1 << 4}, {52532, 1 << 10}, {52532, 1 << 16},
284     };
285     static const struct
286     {
287         size_t initialSize;
288         size_t newSize;
289         size_t alignment;
290     } s_alignedReallocCases[] = {
291         {1, 1, 1},
292         {1, 1, 2},
293         {1, 1, 256},
294         {1, 1, 4096},
295         {1, 1241, 1},
296         {1, 1241, 2},
297         {1, 1241, 256},
298         {1, 1241, 4096},
299         {547389, 234, 1},
300         {547389, 234, 2},
301         {547389, 234, 256},
302         {547389, 234, 4096},
303         {52532, 421523, 1 << 4},
304         {52532, 421523, 1 << 10},
305         {52532, 421523, 1 << 16},
306     };
307 
308     int caseNdx;
309 
310     for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedAllocCases); caseNdx++)
311     {
312         void *const ptr =
313             deAlignedMalloc(s_alignedAllocCases[caseNdx].numBytes, s_alignedAllocCases[caseNdx].alignment);
314 
315         DE_TEST_ASSERT(ptr);
316         DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedAllocCases[caseNdx].alignment));
317 
318         deMemset(ptr, 0xaa, s_alignedAllocCases[caseNdx].numBytes);
319 
320         deAlignedFree(ptr);
321     }
322 
323     for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedReallocCases); caseNdx++)
324     {
325         void *const ptr =
326             deAlignedMalloc(s_alignedReallocCases[caseNdx].initialSize, s_alignedReallocCases[caseNdx].alignment);
327 
328         DE_TEST_ASSERT(ptr);
329         DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
330 
331         deMemset(ptr, 0xaa, s_alignedReallocCases[caseNdx].initialSize);
332 
333         {
334             void *const newPtr =
335                 deAlignedRealloc(ptr, s_alignedReallocCases[caseNdx].newSize, s_alignedReallocCases[caseNdx].alignment);
336             const size_t numPreserved =
337                 s_alignedReallocCases[caseNdx].newSize < s_alignedReallocCases[caseNdx].initialSize ?
338                     s_alignedReallocCases[caseNdx].newSize :
339                     s_alignedReallocCases[caseNdx].initialSize;
340             size_t off;
341 
342             DE_TEST_ASSERT(newPtr);
343             DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
344 
345             for (off = 0; off < numPreserved; off++)
346                 DE_TEST_ASSERT(*((const uint8_t *)newPtr + off) == 0xaa);
347 
348             deAlignedFree(newPtr);
349         }
350     }
351 }
352 
353 DE_END_EXTERN_C
354