From: corinna Date: Mon, 12 Jun 2006 13:59:36 +0000 (+0000) Subject: * winsup.api/user_malloc.c: New file. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=d19cfc4636671728a43ef60543c6c8b7c3b639e5;p=pf3gnuchains%2Fpf3gnuchains3x.git * winsup.api/user_malloc.c: New file. --- diff --git a/winsup/testsuite/ChangeLog b/winsup/testsuite/ChangeLog index 95162a4e9c..8e8cdda2cf 100644 --- a/winsup/testsuite/ChangeLog +++ b/winsup/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2006-06-12 Pierre Humblet Pierre.Humblet@ieee.org + + * winsup.api/user_malloc.c: New file. + 2006-05-30 Christopher Faylor * winsup.api/cygload.h: Increase padding to 32768. diff --git a/winsup/testsuite/winsup.api/user_malloc.c b/winsup/testsuite/winsup.api/user_malloc.c new file mode 100644 index 0000000000..8685f86abc --- /dev/null +++ b/winsup/testsuite/winsup.api/user_malloc.c @@ -0,0 +1,216 @@ +/* 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 +#include +#include +#include +#include +#include + +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++; +} +