3 # Autotest module to verify correct operation of the MinGW aligned
4 # heap memory management API.
8 # Written by Keith Marshall <keith@users.osdn.me>
9 # Copyright (C) 2018, MinGW.org Project
12 # Permission is hereby granted, free of charge, to any person obtaining a
13 # copy of this software and associated documentation files (the "Software"),
14 # to deal in the Software without restriction, including without limitation
15 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 # and/or sell copies of the Software, and to permit persons to whom the
17 # Software is furnished to do so, subject to the following conditions:
19 # The above copyright notice and this permission notice (including the next
20 # paragraph) shall be included in all copies or substantial portions of the
23 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 # AUTHORS OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 # DEALINGS IN THE SOFTWARE.
32 # All tests specified herein are written in the C language.
36 AT_BANNER([Aligned heap memory allocation function checks.])
37 #-----------------------------------------------------------
38 # Implement a collection of tests to exercise the MinGW aligned memory
39 # allocation functions, and confirm that they yield correcly aligned heap
40 # memory blocks, or that they fail appropriately.
42 AT_SETUP([Allocation on valid alignment boundaries])dnl
43 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
44 /* Check that __mingw_aligned_malloc(), and __mingw_aligned_offset_malloc()
45 * return non-NULL pointers, which are numerically exact integer multiples of
46 * any specified alignment. Also gratuitously uses __mingw_free(), but does
47 * not verify its behaviour; this is checked independently.
51 { size_t alignment, status = 0;
52 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
53 { void *ptr = __mingw_aligned_malloc(128, alignment);
54 status |= (ptr != NULL) ? (size_t)(ptr) % alignment : 1;
56 ptr = __mingw_aligned_offset_malloc(128, alignment, 5);
57 status |= (ptr != NULL) ? ((size_t)(ptr) + 5) % alignment : 1;
64 AT_SETUP([Rejection of invalid alignment specifications])dnl
65 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
66 /* Check that __mingw_aligned_malloc(), and __mingw_aligned_offset_malloc()
67 * fail, returning a NULL pointer, and setting errno to EINVAL, when called
68 * with an alignment argument which is not an integer power of two. Again,
69 * this gratuitously uses __mingw_free(), without attempting to verify its
70 * behaviour, which is checked independently.
75 { size_t alignment, status = 0;
76 for( alignment = sizeof (void *); 128 >= alignment; alignment <<= 1 )
77 { void *ptr = __mingw_aligned_malloc(128, alignment - 1);
78 if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
80 ptr = __mingw_aligned_offset_malloc(128, alignment - 1, 5);
81 if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
88 AT_SETUP([Rejection of excessive offset specifications])dnl
89 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
90 /* Check that __mingw_aligned_offset_malloc() fails, returning a NULL
91 * pointer, and setting errno to EINVAL, when called with any value for
92 * its offset argument which is non-zero, and greater than or equal to
93 * the requested size argument.
98 { size_t alignment, status = 0;
99 for( alignment = sizeof (void *); 128 >= alignment; alignment <<= 1 )
100 { void *ptr = __mingw_aligned_offset_malloc(128, alignment, 128);
101 if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
103 ptr = __mingw_aligned_offset_malloc(128, alignment, 132);
104 if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
106 errno = 0; ptr = __mingw_aligned_offset_malloc(0, alignment, 0);
107 if( (ptr == NULL) && (errno == EINVAL) ) status |= 2;
114 AT_BANNER([Aligned heap memory reallocation function checks.])
115 #-------------------------------------------------------------
116 # Implement a collection of tests to exercise the MinGW aligned memory
117 # specific reallocation functions, and confirm that they yield correcly
118 # aligned heap memory blocks, or that they fail appropriately.
120 AT_SETUP([Reallocation of specifically aligned memory])dnl
121 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
122 /* Check that __mingw_aligned_realloc(), and __mingw_aligned_offset_realloc()
123 * correctly reallocate previously allocated aligned memory blocks, preserving
124 * original block content, when called with acceptable arguments.
129 { size_t alignment, status = 0;
130 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
131 { void *p1 = NULL, *p2 = NULL, *p3; size_t size;
132 for( size = 32; 256 >= size; size <<= 1 )
133 { if( (p3 = __mingw_aligned_realloc( p1, size, alignment)) != NULL )
135 if( p2 == NULL ) { strcpy( p1, "Sample text." ); p2 = strdup( p1 ); }
136 status |= p2 ? strcmp( p1, p2 ) | ((size_t)(p1) % alignment) : 1;
140 __mingw_free(p1); __mingw_free(p2);
142 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
143 { void *p1 = NULL, *p2 = NULL, *p3; size_t size;
144 for( size = 32; 256 >= size; size <<= 1 )
145 { if( (p3 = __mingw_aligned_offset_realloc( p1, size, alignment, 5)) != NULL )
147 if( p2 == NULL ) { strcpy( p1, "Sample text." ); p2 = strdup( p1 ); }
148 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 5) % alignment) : 1;
152 __mingw_free(p1); __mingw_free(p2);
158 AT_SETUP([Offset constrained rejection of size reduction])dnl
159 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
160 /* Check that __mingw_aligned_offset_realloc() correctly rejects an attempt
161 * to reduce the size of a previously offset-aligned memory block, when the
162 * resultant size will be insufficient to accommodate the specified offset;
163 * such rejection must be indicated by returning a NULL pointer, with errno
170 { size_t align, status = 0;
171 for( align = 1; 128 >= align; align <<= 1 )
172 { void *p1 = NULL, *p2 = NULL, *p3; size_t size;
173 for( size = 128; size > 0; size >>= 1 )
174 { if( (p3 = __mingw_aligned_offset_realloc( p1, size, align, 16)) != NULL )
175 { if( p3 != p1 ) p1 = p3;
176 if( p2 == NULL ) { strcpy( p1, "Sample text." ); p2 = strdup( p1 ); }
177 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 16) % align) : 2;
178 if( 16 >= size ) status |= 1;
180 else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
182 __mingw_free(p1); __mingw_free(p2);
188 AT_SETUP([Rejection of alignment specification changes])dnl
189 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
190 /* Check that __mingw_aligned_realloc(), and __mingw_aligned_offset_realloc()
191 * fail, returning a NULL pointer, and setting errno to EINVAL, when called
192 * with an alignment parameter which differs from that originally specified,
193 * when the aligned memory block was first allocated.
199 { size_t alignment, status = 0;
200 for( alignment = 8; 128 >= alignment; alignment <<= 1 )
201 { void *p1 = NULL, *p2 = NULL, *p3; size_t size, align;
202 for( size = 128, align = alignment; 256 >= size; size <<= 1, align <<= 1 )
203 { if( (p3 = __mingw_aligned_realloc( p1, size, align)) != NULL )
206 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
207 status |= p2 ? strcmp( p1, p2 ) | ((size_t)(p1) % align) : 2;
211 else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
213 __mingw_free(p1); __mingw_free(p2);
215 for( alignment = 8; 128 >= alignment; alignment <<= 1 )
216 { void *p1 = NULL, *p2 = NULL, *p3; size_t size, align;
217 for( size = 128, align = alignment; 256 >= size; size <<= 1, align <<= 1 )
218 { if( (p3 = __mingw_aligned_offset_realloc( p1, size, align, 5)) != NULL )
221 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
222 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 5) % align) : 2;
226 else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
228 __mingw_free(p1); __mingw_free(p2);
234 AT_SETUP([Rejection of offset specification changes])dnl
235 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
236 /* Check that __mingw_aligned_offset_realloc() fails, returning a NULL
237 * pointer, and setting errno to EINVAL, when called an offset parameter
238 * which differs from that specified when the offset-aligned memory block
239 * was originally allocated.
245 { size_t align, status = 0;
246 for( align = 1; 128 >= align; align <<= 1 )
247 { void *p1 = NULL, *p2 = NULL, *p3; size_t size, offset;
248 for( size = 128, offset = 4; 256 >= size; size <<= 1, offset <<= 1 )
249 { if( (p3 = __mingw_aligned_offset_realloc( p1, size, align, offset)) != NULL )
250 { if( p3 != p1 ) p1 = p3;
252 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
253 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + offset) % align) : 2;
257 else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
259 __mingw_free(p1); __mingw_free(p2);
265 AT_BANNER([Universal heap memory reallocation function checks.])
266 #---------------------------------------------------------------
267 # Implement a collection of tests to exercise the MinGW generic memory
268 # reallocation function, __mingw_realloc(), to confirm that it correctly
269 # discriminates between aligned and regular memory blocks, yields correcly
270 # aligned memory blocks, when appropriate, or that it fails correctly,
273 AT_SETUP([Reallocation of specifically aligned memory])dnl
274 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
275 /* Check that __mingw_realloc() can successfully resize an initially
276 * offset-aligned memory block, preserving its alignment, its offset,
282 { size_t align, status = 0;
283 for( align = 1; 128 >= align; align <<= 1 )
284 { void *p1 = NULL, *p2 = NULL, *p3; size_t size = 64;
285 if( (p1 = __mingw_aligned_offset_malloc( size, align, 16)) != NULL )
286 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
287 for( size = 128; 512 >= size; size <<= 1 )
288 if( (p3 = __mingw_realloc( p1, size )) != NULL )
290 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 16) % align) : 2;
294 __mingw_free(p1); __mingw_free(p2);
300 AT_SETUP([Reallocation of conventionally aligned memory])dnl
301 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
302 /* Check that __mingw_realloc() can successfully resize a memory block
303 * which was originally allocated by malloc(), preserving * its content,
304 * but with neither alignment nor offset constraint.
309 { size_t align, status = 0;
310 for( align = 1; 128 >= align; align <<= 1 )
311 { void *p1 = NULL, *p2 = NULL, *p3; size_t size = 64;
312 if( (p1 = malloc( size )) != NULL )
313 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
314 for( size = 128; 512 >= size; size <<= 1 )
315 if( (p3 = __mingw_realloc( p1, size )) != NULL )
316 { p1 = p3; status |= p2 ? strcmp( p1, p2 ) : 2; }
319 __mingw_free(p1); __mingw_free(p2);
325 AT_SETUP([Offset constrained rejection of size reduction])dnl
326 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
327 /* Check that __mingw_realloc() will decline to resize an originally
328 * offset-aligned memory block, when the requested size is insufficient
329 * to accommodate any data beyond the original offset; the returned
330 * pointer must be NULL, and errno must be set to EINVAL.
336 { size_t align, status = 0;
337 for( align = 1; 128 >= align; align <<= 1 )
338 { void *p1 = NULL, *p2 = NULL, *p3; size_t size = 128;
339 if( (p1 = __mingw_aligned_offset_malloc( size, align, 16)) != NULL )
340 { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
341 for( size = 64; size > 0; size >>= 1 )
342 if( (p3 = __mingw_realloc( p1, size )) != NULL )
344 status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 16) % align) : 2;
345 if( 16 >= size ) status |= 1;
347 else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
349 __mingw_free(p1); __mingw_free(p2);
355 AT_BANNER([Universal heap memory deallocation function checks.])
356 #---------------------------------------------------------------
357 # Implement a collection of tests to exercise the MinGW generic memory
358 # deallocation function, to confirm that it can successfully return both
359 # conventionally allocated and specifically aligned memory to the unused
360 # heap memory pool; additionally, confirm that any of the reallocation
361 # functions will perform a similar function, when allocation size is
364 # MINGW_AT_SKIP_IF_NO_HEAPWALK
365 # ----------------------------
366 # Check that the host operating system supports Microsoft's _heapwalk()
367 # API; (WinNT should do, but Win9x apparently doesn't). For those which
368 # don't, indicate that dependent tests should be skipped.
370 m4_define([MINGW_AT_SKIP_IF_NO_HEAPWALK],dnl)
371 [ _HEAPINFO hmon = {NULL, 0, 0};
372 errno = 0; int status = _heapwalk( &hmon );
373 if( errno == ENOSYS ) return 77;dnl
374 ])# MINGW_AT_SKIP_IF_NO_HEAPWALK
376 # MINGW_AT_VERIFY_ALIGNED_FREE( NAME, METHOD )
377 # --------------------------------------------
378 # Provide a function, try_NAME(), to walk the heap, identifying the base
379 # address of the heap block, if any, which contains a specified (possibly
380 # aligned) heap pointer; invoke METHOD on the specified pointer, then walk
381 # the heap again, to confirm that the original base address either refers
382 # to an unused heap region, or it no longer refers to any heap region,
383 # in either used or unused state, which remains addressable.
385 m4_define([MINGW_AT_VERIFY_ALIGNED_FREE],[dnl
386 int try_$1( void *ptr )
387 { _HEAPINFO hmon = {NULL, 0, 0};
388 if( ptr == NULL ) return 1;
389 while( _heapwalk( &hmon ) == _HEAPOK )
390 { uintptr_t base = (uintptr_t)(hmon._pentry);
391 if( ((uintptr_t)(ptr) >= base) && ((base + hmon._size) >= (uintptr_t)(ptr)) )
392 { if( hmon._useflag != _USEDENTRY ) return 1;
393 $2; ptr = hmon._pentry; hmon._pentry = NULL;
394 while( _heapwalk( &hmon ) == _HEAPOK )
395 if( hmon._pentry == ptr ) return (hmon._useflag == _FREEENTRY) ? 0 : 1;
401 ])# MINGW_AT_VERIFY_ALIGNED_FREE
403 AT_SETUP([Free conventionally aligned heap memory])dnl
404 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
405 /* Check that __mingw_free() can correctly identify a pointer which
406 * was NOT allocated by any MinGW aligned memory allocation function;
407 * when any such pointer can be mapped to a heap block which may have
408 * been allocated by malloc(), or realloc(), free it regardless, and
409 * confirm that it is successfully deallocated.
414 ]MINGW_AT_VERIFY_ALIGNED_FREE([free],[__mingw_free(ptr)])[
417 ]MINGW_AT_SKIP_IF_NO_HEAPWALK[
418 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
419 { if( try_free(malloc(128)) ) return 99; }
424 AT_SETUP([Free specifically aligned heap memory])dnl
425 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
426 /* Check that __mingw_free() can correctly identify a pointer which
427 * WAS allocated by a MinGW aligned memory allocation function; when
428 * any such pointer has been identified, free its underlying heap
429 * memory, and confirm that deallocation is successful.
434 ]MINGW_AT_VERIFY_ALIGNED_FREE([free],[__mingw_free(ptr)])[
437 ]MINGW_AT_SKIP_IF_NO_HEAPWALK[
438 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
439 { if( try_free(__mingw_aligned_malloc(128, alignment)) ) return 99;
440 if( try_free(__mingw_aligned_offset_malloc(128, alignment, 5)) ) return 99;
446 AT_SETUP([Free by reallocation to zero size])dnl
447 AT_KEYWORDS([C memalign])MINGW_AT_CHECK_RUN([[[
448 /* Check that __mingw_realloc() can reproduce the effect of __mingw_free(),
449 * in respect of any heap memory allocation, when called with a requested size
450 * of zero; similarly, check that each of the __mingw_aligned_realloc(), and
451 * __mingw_aligned_offset_realloc() functions reproduce the same effect, when
452 * invoked to request resizing to zero, on blocks with correspondingly matched
453 * alignment, and offset arguments.
455 * Note that this is a Microsoft compatibility check; hopefully, no user
456 * will ever write code which depends on this anomalous behaviour.
462 ]MINGW_AT_VERIFY_ALIGNED_FREE([realloc],dnl
463 [__mingw_realloc(ptr,0)])[
464 ]MINGW_AT_VERIFY_ALIGNED_FREE([aligned_realloc],dnl
465 [__mingw_aligned_realloc(ptr,0,alignment)])[
466 ]MINGW_AT_VERIFY_ALIGNED_FREE([offset_realloc],dnl
467 [__mingw_aligned_offset_realloc(ptr,0,alignment,5)])[
469 {]MINGW_AT_SKIP_IF_NO_HEAPWALK[
470 for( alignment = 1; 128 >= alignment; alignment <<= 1 )
471 { if( try_realloc(__mingw_aligned_malloc(128, alignment)) )
473 if( try_realloc(__mingw_aligned_offset_malloc(128, alignment, 5)) )
475 if( try_offset_realloc(__mingw_aligned_offset_malloc(128, alignment, 5)) )
477 if( try_aligned_realloc(__mingw_aligned_malloc(128, alignment)) )
479 if( try_realloc(malloc(128)) )
486 # vim: filetype=config formatoptions=croql
487 # $RCSfile$: end of file