300 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* malloc_wrapper.cc
 | |
| 
 | |
| 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 "cygerrno.h"
 | |
| #include "security.h"
 | |
| #include "path.h"
 | |
| #include "fhandler.h"
 | |
| #include "dtable.h"
 | |
| #include "perprocess.h"
 | |
| #include "miscfuncs.h"
 | |
| #include "cygmalloc.h"
 | |
| #include <malloc.h>
 | |
| extern "C" struct mallinfo dlmallinfo ();
 | |
| 
 | |
| /* 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 bool use_internal = true;
 | |
| static bool internal_malloc_determined;
 | |
| 
 | |
| /* These routines are used by the application if it
 | |
|    doesn't provide its own malloc. */
 | |
| 
 | |
| extern "C" void
 | |
| free (void *p)
 | |
| {
 | |
|   malloc_printf ("(%p), called by %p", p, caller_return_address ());
 | |
|   if (!use_internal)
 | |
|     user_data->free (p);
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       dlfree (p);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| extern "C" void *
 | |
| malloc (size_t size)
 | |
| {
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     res = user_data->malloc (size);
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlmalloc (size);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
|   malloc_printf ("(%ld) = %p, called by %p", size, res,
 | |
| 					     caller_return_address ());
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" void *
 | |
| realloc (void *p, size_t size)
 | |
| {
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     res = user_data->realloc (p, size);
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlrealloc (p, size);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
|   malloc_printf ("(%p, %ld) = %p, called by %p", p, size, res,
 | |
|   						 caller_return_address ());
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /* BSD extension:  Same as realloc, just if it fails to allocate new memory,
 | |
|    it frees the incoming pointer. */
 | |
| extern "C" void *
 | |
| reallocf (void *p, size_t size)
 | |
| {
 | |
|   void *res = realloc (p, size);
 | |
|   if (!res && p)
 | |
|     free (p);
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" void *
 | |
| calloc (size_t nmemb, size_t size)
 | |
| {
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     res = user_data->calloc (nmemb, size);
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlcalloc (nmemb, size);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
|   malloc_printf ("(%ld, %ld) = %p, called by %p", nmemb, size, res,
 | |
| 						  caller_return_address ());
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| posix_memalign (void **memptr, size_t alignment, size_t bytes)
 | |
| {
 | |
|   save_errno save;
 | |
| 
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     return user_data->posix_memalign (memptr, alignment, bytes);
 | |
|   if ((alignment & (alignment - 1)) != 0)
 | |
|     return EINVAL;
 | |
|   __malloc_lock ();
 | |
|   res = dlmemalign (alignment, bytes);
 | |
|   __malloc_unlock ();
 | |
|   if (!res)
 | |
|     return ENOMEM;
 | |
|   *memptr = res;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| extern "C" void *
 | |
| memalign (size_t alignment, size_t bytes)
 | |
| {
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       set_errno (ENOSYS);
 | |
|       res = NULL;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlmemalign (alignment, bytes);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" void *
 | |
| valloc (size_t bytes)
 | |
| {
 | |
|   void *res;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       set_errno (ENOSYS);
 | |
|       res = NULL;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlvalloc (bytes);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" size_t
 | |
| malloc_usable_size (void *p)
 | |
| {
 | |
|   size_t res;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       set_errno (ENOSYS);
 | |
|       res = 0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlmalloc_usable_size (p);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| malloc_trim (size_t pad)
 | |
| {
 | |
|   size_t res;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       set_errno (ENOSYS);
 | |
|       res = 0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlmalloc_trim (pad);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| mallopt (int p, int v)
 | |
| {
 | |
|   int res;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       set_errno (ENOSYS);
 | |
|       res = 0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       res = dlmallopt (p, v);
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| extern "C" void
 | |
| malloc_stats ()
 | |
| {
 | |
|   if (!use_internal)
 | |
|     set_errno (ENOSYS);
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       dlmalloc_stats ();
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| extern "C" struct mallinfo
 | |
| mallinfo ()
 | |
| {
 | |
|   struct mallinfo m;
 | |
|   if (!use_internal)
 | |
|     {
 | |
|       memset (&m, 0, sizeof m);
 | |
|       set_errno (ENOSYS);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       __malloc_lock ();
 | |
|       m = dlmallinfo ();
 | |
|       __malloc_unlock ();
 | |
|     }
 | |
| 
 | |
|   return m;
 | |
| }
 | |
| 
 | |
| extern "C" char *
 | |
| strdup (const char *s)
 | |
| {
 | |
|   char *p;
 | |
|   size_t len = strlen (s) + 1;
 | |
|   if ((p = (char *) malloc (len)) != NULL)
 | |
|     memcpy (p, s, len);
 | |
|   return p;
 | |
| }
 | |
| 
 | |
| /* 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.  */
 | |
| 
 | |
| muto NO_COPY mallock;
 | |
| 
 | |
| void
 | |
| malloc_init ()
 | |
| {
 | |
|   mallock.init ("mallock");
 | |
| 
 | |
|   /* Check if malloc is provided by application. If so, redirect all
 | |
|      calls to 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 (!internal_malloc_determined)
 | |
|     {
 | |
|       extern void *_sigfe_malloc;
 | |
|       /* Decide if we are using our own version of malloc by testing the import
 | |
| 	 address from user_data.  */
 | |
|       use_internal = user_data->malloc == malloc
 | |
| 		     || import_address (user_data->malloc) == &_sigfe_malloc;
 | |
|       malloc_printf ("using %s malloc", use_internal ? "internal" : "external");
 | |
|       internal_malloc_determined = true;
 | |
|     }
 | |
| }
 | |
| 
 | |
| extern "C" void
 | |
| __set_ENOMEM ()
 | |
| {
 | |
|   set_errno (ENOMEM);
 | |
| }
 |