OSDN Git Service

7b8baf8d5b9d226a1d31865498e8686a0904df95
[mingw/mingw-org-wsl.git] / mingwrt / tests / memalign.at
1 # memalign.at
2 #
3 # Autotest module to verify correct operation of the MinGW aligned
4 # heap memory management API.
5 #
6 # $Id$
7 #
8 # Written by Keith Marshall <keith@users.osdn.me>
9 # Copyright (C) 2018, MinGW.org Project
10 #
11 #
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:
18 #
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
21 # Software.
22 #
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.
30 #
31 #
32 # All tests specified herein are written in the C language.
33 #
34 MINGW_AT_LANG([C])
35
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.
41
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.
48  */
49 #include <malloc.h>
50 int main()
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;
55     __mingw_free(ptr);
56     ptr = __mingw_aligned_offset_malloc(128, alignment, 5);
57     status |= (ptr != NULL) ? ((size_t)(ptr) + 5) % alignment : 1;
58     __mingw_free(ptr);
59   }
60   return status;
61 }]]])dnl
62 AT_CLEANUP
63
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.
71  */
72 #include <malloc.h>
73 #include <errno.h>
74 int main()
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;
79     __mingw_free(ptr);
80     ptr = __mingw_aligned_offset_malloc(128, alignment - 1, 5);
81     if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
82     __mingw_free(ptr);
83   }
84   return status;
85 }]]])dnl
86 AT_CLEANUP
87
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.
94  */
95 #include <malloc.h>
96 #include <errno.h>
97 int main()
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;
102     __mingw_free(ptr);
103     ptr = __mingw_aligned_offset_malloc(128, alignment, 132);
104     if( (ptr != NULL) || (errno != EINVAL) ) status = 1;
105     __mingw_free(ptr);
106     errno = 0; ptr = __mingw_aligned_offset_malloc(0, alignment, 0);
107     if( (ptr == NULL) && (errno == EINVAL) ) status |= 2;
108     __mingw_free(ptr);
109   }
110   return status;
111 }]]])dnl
112 AT_CLEANUP
113
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.
119
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.
125  */
126 #include <malloc.h>
127 #include <string.h>
128 int main()
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 )
134       { p1 = p3;
135         if( p2 == NULL ) { strcpy( p1, "Sample text." ); p2 = strdup( p1 ); }
136         status |= p2 ? strcmp( p1, p2 ) | ((size_t)(p1) % alignment) : 1;
137       }
138       else status |= 1;
139     }
140     __mingw_free(p1); __mingw_free(p2);
141   }
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 )
146       { p1 = p3;
147         if( p2 == NULL ) { strcpy( p1, "Sample text." ); p2 = strdup( p1 ); }
148         status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 5) % alignment) : 1;
149       }
150       else status |= 1;
151     }
152     __mingw_free(p1); __mingw_free(p2);
153   }
154   return status;
155 }]]])dnl
156 AT_CLEANUP
157
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
164  * set to EINVAL.
165  */
166 #include <malloc.h>
167 #include <string.h>
168 #include <errno.h>
169 int main()
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;
179       }
180       else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
181     }
182     __mingw_free(p1); __mingw_free(p2);
183   }
184   return status;
185 }]]])dnl
186 AT_CLEANUP
187
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.
194  */
195 #include <malloc.h>
196 #include <string.h>
197 #include <errno.h>
198 int main()
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 )
204       { p1 = p3;
205         if( p2 == NULL )
206         { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
207           status |= p2 ? strcmp( p1, p2 ) | ((size_t)(p1) % align) : 2;
208         }
209         else status |= 1;
210       }
211       else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
212     }
213     __mingw_free(p1); __mingw_free(p2);
214   }
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 )
219       { p1 = p3;
220         if( p2 == NULL )
221         { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
222           status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 5) % align) : 2;
223         }
224         else status |= 1;
225       }
226       else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
227     }
228     __mingw_free(p1); __mingw_free(p2);
229   }
230   return status;
231 }]]])dnl
232 AT_CLEANUP
233
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.
240  */
241 #include <malloc.h>
242 #include <string.h>
243 #include <errno.h>
244 int main()
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;
251         if( p2 == NULL )
252         { strcpy( p1, "Sample text." ); p2 = strdup( p1 );
253           status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + offset) % align) : 2;
254         }
255         else status |= 1;
256       }
257       else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
258     }
259     __mingw_free(p1); __mingw_free(p2);
260   }
261   return status;
262 }]]])dnl
263 AT_CLEANUP
264
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,
271 # when expected.
272 #
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,
277  * and its content.
278  */
279 #include <malloc.h>
280 #include <string.h>
281 int main()
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 )
289         { p1 = p3;
290           status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 16) % align) : 2;
291         }
292         else status |= 1;
293     }
294     __mingw_free(p1); __mingw_free(p2);
295   }
296   return status;
297 }]]])dnl
298 AT_CLEANUP
299
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.
305  */
306 #include <malloc.h>
307 #include <string.h>
308 int main()
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; }
317         else status |= 1;
318     }
319     __mingw_free(p1); __mingw_free(p2);
320   }
321   return status;
322 }]]])dnl
323 AT_CLEANUP
324
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.
331  */
332 #include <malloc.h>
333 #include <string.h>
334 #include <errno.h>
335 int main()
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 )
343         { p1 = p3;
344           status |= p2 ? strcmp( p1, p2 ) | (((size_t)(p1) + 16) % align) : 2;
345           if( 16 >= size ) status |= 1;
346         }
347         else if( (p2 == NULL) || (errno != EINVAL) ) status |= 4;
348     }
349     __mingw_free(p1); __mingw_free(p2);
350   }
351   return status;
352 }]]])dnl
353 AT_CLEANUP
354
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
362 # reduced to zero.
363
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.
369 #
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
375
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.
384 #
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;
396       return 0;
397     }
398   }
399   return 1;
400 }
401 ])# MINGW_AT_VERIFY_ALIGNED_FREE
402
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.
410  */
411 #include <stdint.h>
412 #include <malloc.h>
413 #include <errno.h>
414 ]MINGW_AT_VERIFY_ALIGNED_FREE([free],[__mingw_free(ptr)])[
415 int main()
416 { size_t alignment;
417  ]MINGW_AT_SKIP_IF_NO_HEAPWALK[
418   for( alignment = 1; 128 >= alignment; alignment <<= 1 )
419   { if( try_free(malloc(128)) ) return 99; }
420   return 0;
421 }]]])dnl
422 AT_CLEANUP
423
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.
430  */
431 #include <stdint.h>
432 #include <malloc.h>
433 #include <errno.h>
434 ]MINGW_AT_VERIFY_ALIGNED_FREE([free],[__mingw_free(ptr)])[
435 int main()
436 { size_t alignment;
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;
441   }
442   return 0;
443 }]]])dnl
444 AT_CLEANUP
445
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.
454  *
455  * Note that this is a Microsoft compatibility check; hopefully, no user
456  * will ever write code which depends on this anomalous behaviour.
457  */
458 #include <stdint.h>
459 #include <malloc.h>
460 #include <errno.h>
461 size_t alignment;
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)])[
468 int main()
469 {]MINGW_AT_SKIP_IF_NO_HEAPWALK[
470   for( alignment = 1; 128 >= alignment; alignment <<= 1 )
471   { if( try_realloc(__mingw_aligned_malloc(128, alignment)) )
472       return 99;
473     if( try_realloc(__mingw_aligned_offset_malloc(128, alignment, 5)) )
474       return 99;
475     if( try_offset_realloc(__mingw_aligned_offset_malloc(128, alignment, 5)) )
476       return 99;
477     if( try_aligned_realloc(__mingw_aligned_malloc(128, alignment)) )
478       return 99;
479     if( try_realloc(malloc(128)) )
480       return 99;
481   }
482   return 0;
483 }]]])dnl
484 AT_CLEANUP
485
486 # vim: filetype=config formatoptions=croql
487 # $RCSfile$: end of file