217 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Test of external malloc, calloc, realloc and free capability */
 | |
| 
 | |
| #if 1
 | |
| #include "test.h"
 | |
| #include "usctest.h"
 | |
| #else
 | |
| enum {TPASS, TFAIL, TBROK, TINFO};
 | |
| #define tst_resm(xxx, yyy...) printf(yyy), printf(" RES %d\n", xxx)
 | |
| #define tst_brkm(xxx, yyy, zzz...) printf(zzz), printf(" RES %d\n", xxx)
 | |
| #define tst_exit()
 | |
| int Tst_count;
 | |
| #endif
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <strings.h>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| const char *TCID = "malloc";    /* Test program identifier. */
 | |
| int TST_TOTAL = 2;              /* Total number of test cases. */
 | |
| extern int Tst_count;           /* Test Case counter for tst_* routines */
 | |
| 
 | |
| /* Main test.
 | |
|    Verbose mode if argc > 0
 | |
|    Note that malloc and friends are also called by Cygwin before main,
 | |
|    and that malloc can call getenv. */
 | |
| 
 | |
| int malloc_error = 0, realloc_error = 0, free_error = 0; 
 | |
| int calloc_count = 0, malloc_count = 0, realloc_count = 0, free_count = 0;
 | |
| 
 | |
| void
 | |
| cleanup (void)
 | |
| {
 | |
|   tst_exit(); 
 | |
| }
 | |
| 
 | |
| int
 | |
| syncwithchild (pid_t pid, int expected_exit_status)
 | |
| {
 | |
|   int status;
 | |
| 
 | |
|   if (waitpid (pid, &status, 0) != pid)
 | |
|     {
 | |
|       tst_brkm (TBROK, cleanup, "Wait for child: %s", strerror (errno));
 | |
|       return 1;
 | |
|     }
 | |
|   if (!WIFEXITED (status))
 | |
|     {
 | |
|       tst_brkm (TBROK, cleanup, "Child had abnormal exit");
 | |
|       return 1;
 | |
|     }
 | |
|   if (WEXITSTATUS (status) != expected_exit_status)
 | |
|     {
 | |
|       tst_brkm (TFAIL, cleanup, "Child had exit status %d != %d",
 | |
| 		WEXITSTATUS (status), expected_exit_status);
 | |
|       return 1;
 | |
|     }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| void * mallocX (size_t size);
 | |
| void * callocX (size_t nmemb, size_t size);
 | |
| void * reallocX (void * ptr, size_t size);
 | |
| void freeX(void *);
 | |
| 
 | |
| #define malloc mallocX
 | |
| #define calloc callocX
 | |
| #define realloc reallocX
 | |
| #define free freeX
 | |
| #endif
 | |
| 
 | |
| int main (int argc, char * argv[])
 | |
| { 
 | |
|   void * ptr;
 | |
|   int error = 0;
 | |
|   pid_t pid;
 | |
| 
 | |
|   Tst_count = 0;
 | |
| 
 | |
|   tst_resm(TINFO, "Testing if external malloc works. ppid %d", getppid());
 | |
| 
 | |
|   ptr = malloc (16);
 | |
|   ptr = calloc (1, 16);
 | |
|   ptr = realloc (ptr, 24);
 | |
|   free (ptr);
 | |
| 
 | |
|   error = (malloc_count == 0 || calloc_count == 0 || realloc_count == 0 || free_count == 0);
 | |
| 
 | |
|   if (error || argc > 1)
 | |
|     {
 | |
|       printf ("malloc_count %d, calloc_count %d, realloc_count %d, free_count %d\n", 
 | |
| 	      malloc_count, calloc_count, realloc_count, free_count);
 | |
|       printf ("malloc_error %d, realloc_error %d, free_error %d\n",
 | |
| 	      malloc_error, realloc_error, free_error);
 | |
|     }
 | |
|   tst_resm (!error ? TPASS : TFAIL, "Running in pid %d", getpid());
 | |
| 
 | |
|   /* If run from Windows, run also from Cygwin */
 | |
|   if (getppid() == 1)
 | |
|     {
 | |
|       tst_resm(TINFO, "Ready to test if malloc works from Cygwin");
 | |
| 
 | |
|       if ((pid = fork()) == 0)
 | |
| 	{
 | |
| 	  tst_resm(TINFO, "Ready to exec with pid %d\n", getpid());
 | |
| 	  error = execl(argv[0], argv[0], argc > 1? argv[1]:NULL, NULL);
 | |
| 	  exit(error);
 | |
| 	}
 | |
|       else if (pid < 0)
 | |
| 	tst_brkm (TBROK, cleanup, "Fork failed: %s", strerror (errno));
 | |
|       else
 | |
| 	{
 | |
| 	  error = syncwithchild (pid, 0);
 | |
| 	  tst_resm (!error ? TPASS : TFAIL, "Running in pid %d", pid);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   tst_exit ();
 | |
| }
 | |
| 
 | |
| /****************************************
 | |
| Actual malloc & friends implementation 
 | |
| ****************************************/
 | |
| 
 | |
| typedef unsigned long long ull;
 | |
|  
 | |
| #define SIZE (1024*1024ULL) /* long long */ 
 | |
| ull buffer[SIZE]; 
 | |
| ull * current = buffer;
 | |
| 
 | |
| static int is_valid (void * ptr)
 | |
| {
 | |
|   unsigned int iptr = (unsigned int) ptr;
 | |
|   ull * ullptr = (ull *) ptr;
 | |
| 
 | |
|   iptr = (iptr / sizeof(ull)) * sizeof(ull);
 | |
|   if (iptr != (int) ptr)
 | |
|     return 0;
 | |
|   if (--ullptr < buffer || ullptr[0] > SIZE || ullptr  + ullptr[0]  > current)
 | |
|     return 0;
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| void * malloc (size_t size)
 | |
| {
 | |
|   ull llsize = (size + 2 * sizeof (ull) - 1) / sizeof (ull);
 | |
|   static char * envptr;
 | |
|   void * ret;
 | |
|   
 | |
|   /* Make sure getenv works */
 | |
|   if (!envptr)
 | |
|     envptr = getenv ("PATH");
 | |
| 
 | |
|   malloc_count++;
 | |
|   if (current + llsize >= buffer + SIZE) 
 | |
|     {
 | |
|       malloc_error++;
 | |
|       errno = ENOMEM;
 | |
|       return NULL;
 | |
|     }
 | |
|   *current = llsize;
 | |
|   ret = (void *) (current + 1);
 | |
|   current += llsize;
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void * calloc (size_t nmemb, size_t size) 
 | |
| {
 | |
|   calloc_count++;
 | |
|   void * ptr = malloc (nmemb * size);
 | |
|   malloc_count--;
 | |
|   if (ptr)
 | |
|     memset(ptr, 0, nmemb * size);
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| void * realloc (void * ptr, size_t size)
 | |
| {
 | |
|   const ull ullsize = (size + 2 * sizeof (ull) - 1) / sizeof (ull);
 | |
|   ull * const ullptr = (ull *) ptr;
 | |
|   void * newptr;
 | |
|   
 | |
|   realloc_count++;
 | |
|   
 | |
|   if (ptr)
 | |
|     {
 | |
|       if (!is_valid (ptr))
 | |
| 	{
 | |
| 	  realloc_error++;
 | |
| 	  errno = ENOMEM;
 | |
| 	  return NULL;
 | |
| 	}  
 | |
|       if (ullptr[-1] >= ullsize)
 | |
| 	return ptr;
 | |
|     }
 | |
| 
 | |
|   newptr = malloc (size);
 | |
|   malloc_count--;
 | |
|   
 | |
|   if (ptr && newptr)
 | |
|     memcpy (newptr, ptr, size);
 | |
|   
 | |
|   return newptr;
 | |
| }
 | |
| 
 | |
| void free (void * x)
 | |
| {
 | |
|   free_count++;
 | |
|   if (x && ! is_valid (x))
 | |
|       free_error++;
 | |
| }
 | |
| 
 |