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++;
|
||
|
}
|
||
|
|