mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			164 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Test for memalign chunk reuse.
 | |
|    Copyright (C) 2022-2025 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <https://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <malloc.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| #include <array_length.h>
 | |
| #include <libc-pointer-arith.h>
 | |
| #include <support/check.h>
 | |
| 
 | |
| typedef struct TestCase {
 | |
|   size_t size;
 | |
|   size_t alignment;
 | |
|   void *ptr1;
 | |
|   void *ptr2;
 | |
| } TestCase;
 | |
| 
 | |
| static TestCase tcache_allocs[] = {
 | |
|   { 24, 32, NULL, NULL },
 | |
|   { 24, 64, NULL, NULL },
 | |
|   { 128, 128, NULL, NULL },
 | |
|   { 500, 128, NULL, NULL }
 | |
| };
 | |
| #define TN array_length (tcache_allocs)
 | |
| 
 | |
| static TestCase large_allocs[] = {
 | |
|   { 23450, 64, NULL, NULL },
 | |
|   { 23450, 64, NULL, NULL },
 | |
|   { 23550, 64, NULL, NULL },
 | |
|   { 23550, 64, NULL, NULL },
 | |
|   { 23650, 64, NULL, NULL },
 | |
|   { 23650, 64, NULL, NULL },
 | |
|   { 33650, 64, NULL, NULL },
 | |
|   { 33650, 64, NULL, NULL }
 | |
| };
 | |
| #define LN array_length (large_allocs)
 | |
| 
 | |
| void *p;
 | |
| 
 | |
| /* Sanity checks, ancillary to the actual test.  */
 | |
| #define CHECK(p,a) \
 | |
|   if (p == NULL || !PTR_IS_ALIGNED (p, a)) \
 | |
|     FAIL_EXIT1 ("NULL or misaligned memory detected.\n");
 | |
| 
 | |
| static int
 | |
| do_test (void)
 | |
| {
 | |
|   int i, j;
 | |
|   int count;
 | |
|   void *ptr[10];
 | |
|   void *p;
 | |
| 
 | |
|   /* TCache test.  */
 | |
| 
 | |
|   for (i = 0; i < TN; ++ i)
 | |
|     {
 | |
|       size_t sz2;
 | |
| 
 | |
|       tcache_allocs[i].ptr1 = memalign (tcache_allocs[i].alignment, tcache_allocs[i].size);
 | |
|       CHECK (tcache_allocs[i].ptr1, tcache_allocs[i].alignment);
 | |
|       sz2 = malloc_usable_size (tcache_allocs[i].ptr1);
 | |
|       free (tcache_allocs[i].ptr1);
 | |
| 
 | |
|       /* This should return the same chunk as was just free'd.  */
 | |
|       tcache_allocs[i].ptr2 = memalign (tcache_allocs[i].alignment, sz2);
 | |
|       CHECK (tcache_allocs[i].ptr2, tcache_allocs[i].alignment);
 | |
|       free (tcache_allocs[i].ptr2);
 | |
| 
 | |
|       TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
 | |
|     }
 | |
| 
 | |
|   /* Test for non-head tcache hits.  This exercises the memalign
 | |
|      scanning code to find matching allocations.  */
 | |
|   for (i = 0; i < array_length (ptr); ++ i)
 | |
|     {
 | |
|       if (i == 4)
 | |
| 	{
 | |
| 	  ptr[i] = memalign (64, 256);
 | |
| 	  CHECK (ptr[i], 64);
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  ptr[i] = malloc (256);
 | |
| 	  CHECK (ptr[i], 4);
 | |
| 	}
 | |
|     }
 | |
|   for (i = 0; i < array_length (ptr); ++ i)
 | |
|     free (ptr[i]);
 | |
| 
 | |
|   p = memalign (64, 256);
 | |
|   CHECK (p, 64);
 | |
| 
 | |
|   count = 0;
 | |
|   for (i = 0; i < 10; ++ i)
 | |
|     if (ptr[i] == p)
 | |
|       ++ count;
 | |
|   free (p);
 | |
|   TEST_VERIFY (count > 0);
 | |
| 
 | |
|   /* Large bins test.  This verifies that the over-allocated parts
 | |
|      that memalign releases for future allocations can be reused by
 | |
|      memalign itself at least in some cases.  */
 | |
| 
 | |
|   for (i = 0; i < LN; ++ i)
 | |
|     {
 | |
|       large_allocs[i].ptr1 = memalign (large_allocs[i].alignment, large_allocs[i].size);
 | |
|       CHECK (large_allocs[i].ptr1, large_allocs[i].alignment);
 | |
|       /* Keep chunks from combining by fragmenting the heap.  */
 | |
|       p = malloc (512);
 | |
|       CHECK (p, 4);
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < LN; ++ i)
 | |
|     free (large_allocs[i].ptr1);
 | |
| 
 | |
|   /* Force the unsorted bins to be scanned and moved to small/large
 | |
|      bins.  */
 | |
|   p = malloc (60000);
 | |
| 
 | |
|   for (i = 0; i < LN; ++ i)
 | |
|     {
 | |
|       large_allocs[i].ptr2 = memalign (large_allocs[i].alignment, large_allocs[i].size);
 | |
|       CHECK (large_allocs[i].ptr2, large_allocs[i].alignment);
 | |
|     }
 | |
| 
 | |
|   count = 0;
 | |
|   for (i = 0; i < LN; ++ i)
 | |
|     {
 | |
|       int ok = 0;
 | |
|       for (j = 0; j < LN; ++ j)
 | |
| 	if (large_allocs[i].ptr1 == large_allocs[j].ptr2)
 | |
| 	  ok = 1;
 | |
|       if (ok == 1)
 | |
| 	count ++;
 | |
|     }
 | |
| 
 | |
|   /* The allocation algorithm is complicated outside of the memalign
 | |
|      logic, so just make sure it's working for most of the
 | |
|      allocations.  This avoids possible boundary conditions with
 | |
|      empty/full heaps.  */
 | |
|   TEST_VERIFY (count > LN / 2);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #include <support/test-driver.c>
 |