/* malloc.cc for WIN32. Copyright 1996, 1997, 1998 Cygnus Solutions. Written by Steve Chamberlain of Cygnus Support sac@cygnus.com This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include /* we provide these stubs to call into a user's provided malloc if there is one - otherwise functions we provide - like strdup will cause problems if malloced on our heap and free'd on theirs. */ static int export_malloc_called = 0; static int use_internal_malloc = 1; #undef in #undef out #define in(x) #define out(x) #ifdef MALLOC_DEBUG extern "C" void * _sbrk (size_t incr_arg); #if 0 extern "C" void * _sbrk_r (struct _reent *, size_t incr_arg) { return _sbrk (incr_arg); } #endif extern "C" void * _malloc_r (struct _reent *, size_t size) { export_malloc_called = 1; return malloc (size); } #undef malloc extern "C" void * _calloc_r (struct _reent *, size_t nmemb, size_t size) { export_malloc_called = 1; return calloc (nmemb, size); } #undef calloc extern "C" void _free_r (struct _reent *, void *p) { export_malloc_called = 1; free (p); } #undef free extern "C" void * _realloc_r (struct _reent *, void *p, size_t size) { export_malloc_called = 1; return realloc (p, size); } #undef realloc extern "C" char * strdup_dbg (const char *s, const char *file, int line) { char *p; export_malloc_called = 1; if ((p = (char *) malloc_dbg (strlen (s) + 1, file, line)) != NULL) strcpy (p, s); return p; } #undef strdup extern "C" char * strdup (const char *s) { return strdup_dbg (s, __FILE__, __LINE__); } #else /* Call though the application pointer, which either points to export_malloc, or the application's own version. */ void * malloc (size_t size) { void *res; res = user_data->malloc (size); return res; } void free (void *p) { user_data->free (p); } void * realloc (void *p, size_t size) { void *res; res = user_data->realloc (p, size); return res; } void * calloc (size_t nmemb, size_t size) { void *res; res = user_data->calloc (nmemb, size); return res; } #endif /* These routines are used by the application if it doesn't provide its own malloc. */ extern "C" void export_free (void *p) { malloc_printf ("(%p), called by %x", p, ((int *)&p)[-1]); if (use_internal_malloc) _free_r (_impure_ptr, p); else user_data->free (p); } extern "C" void * export_malloc (int size) { void *res; export_malloc_called = 1; if (use_internal_malloc) res = _malloc_r (_impure_ptr, size); else res = user_data->malloc (size); malloc_printf ("(%d) = %x, called by %x", size, res, ((int *)&size)[-1]); return res; } extern "C" void * export_realloc (void *p, int size) { void *res; if (use_internal_malloc) res = _realloc_r (_impure_ptr, p, size); else res = user_data->realloc (p, size); malloc_printf ("(%x, %d) = %x, called by %x", p, size, res, ((int *)&p)[-1]); return res; } extern "C" void * export_calloc (size_t nmemb, size_t size) { void *res; if (use_internal_malloc) res = _calloc_r (_impure_ptr, nmemb, size); else res = user_data->calloc (nmemb, size); malloc_printf ("(%d, %d) = %x, called by %x", nmemb, size, res, ((int *)&nmemb)[-1]); return res; } /* We use a critical section to lock access to the malloc data structures. This permits malloc to be called from different threads. Note that it does not make malloc reentrant, and it does not permit a signal handler to call malloc. The malloc code in newlib will call __malloc_lock and __malloc_unlock at appropriate times. */ static NO_COPY CRITICAL_SECTION malloc_critical_section; void malloc_init () { InitializeCriticalSection (&malloc_critical_section); /* Check if mallock is provided by application. If so, redirect all calls to export_malloc/free/realloc to application provided. This may happen if some other dll calls cygwin's malloc, but main code provides its own malloc */ if (!user_data->forkee) { #ifdef MALLOC_DEBUG _free_r (NULL, _malloc_r (NULL, 16)); #else free (malloc (16)); #endif if (!export_malloc_called) use_internal_malloc = 0; } } extern "C" void __malloc_lock (struct _reent *ptr) { SetResourceLock(LOCK_MEMORY_LIST,WRITE_LOCK|READ_LOCK," __malloc_lock"); } extern "C" void __malloc_unlock (struct _reent *ptr) { ReleaseResourceLock(LOCK_MEMORY_LIST,WRITE_LOCK|READ_LOCK," __malloc_unlock"); }