Cygwin: add newgrp release notes
[newlib-cygwin.git] / winsup / cygwin / mm / malloc_wrapper.cc
blobde3cf7ddc19e7c2718e5c1a7e27889568f929517
1 /* malloc_wrapper.cc
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "cygerrno.h"
11 #include "security.h"
12 #include "path.h"
13 #include "fhandler.h"
14 #include "dtable.h"
15 #include "perprocess.h"
16 #include "miscfuncs.h"
17 #include "cygmalloc.h"
18 #include <malloc.h>
19 extern "C" struct mallinfo dlmallinfo ();
21 /* we provide these stubs to call into a user's
22 provided malloc if there is one - otherwise
23 functions we provide - like strdup will cause
24 problems if malloced on our heap and free'd on theirs.
27 static bool use_internal = true;
28 static bool internal_malloc_determined;
30 /* Helper function to generate the correct caller address. For external
31 calls, the return address on the stack is _sigbe. In that case the
32 actual caller return address is on the cygtls stack. Use this function
33 via the macro caller_return_address. */
34 extern "C" void _sigbe ();
36 static inline void *
37 __caller_return_address (void *builtin_ret_addr)
39 return builtin_ret_addr == &_sigbe
40 ? (void *) _my_tls.retaddr () : builtin_ret_addr;
43 #define caller_return_address() \
44 __caller_return_address (__builtin_return_address (0))
45 void * __caller_return_address (void *);
47 /* Return an address from the import jmp table of main program. */
48 static inline void *
49 import_address (void *imp)
51 __try
53 if (*((uint16_t *) imp) == 0x25ff)
55 const char *ptr = (const char *) imp;
56 const uintptr_t *jmpto = (uintptr_t *)
57 (ptr + 6 + *(int32_t *)(ptr + 2));
58 return (void *) *jmpto;
61 __except (NO_ERROR) {}
62 __endtry
63 return NULL;
66 /* These routines are used by the application if it
67 doesn't provide its own malloc. */
69 extern "C" void
70 free (void *p)
72 malloc_printf ("(%p), called by %p", p, caller_return_address ());
73 if (!use_internal)
74 user_data->free (p);
75 else
77 __malloc_lock ();
78 dlfree (p);
79 __malloc_unlock ();
83 extern "C" void *
84 malloc (size_t size)
86 void *res;
87 if (!use_internal)
88 res = user_data->malloc (size);
89 else
91 __malloc_lock ();
92 res = dlmalloc (size);
93 __malloc_unlock ();
95 malloc_printf ("(%ld) = %p, called by %p", size, res,
96 caller_return_address ());
97 return res;
100 extern "C" void *
101 realloc (void *p, size_t size)
103 void *res;
104 if (!use_internal)
105 res = user_data->realloc (p, size);
106 else
108 __malloc_lock ();
109 res = dlrealloc (p, size);
110 __malloc_unlock ();
112 malloc_printf ("(%p, %ld) = %p, called by %p", p, size, res,
113 caller_return_address ());
114 return res;
117 /* BSD extension: Same as realloc, just if it fails to allocate new memory,
118 it frees the incoming pointer. */
119 extern "C" void *
120 reallocf (void *p, size_t size)
122 void *res = realloc (p, size);
123 if (!res && p)
124 free (p);
125 return res;
128 extern "C" void *
129 calloc (size_t nmemb, size_t size)
131 void *res;
132 if (!use_internal)
133 res = user_data->calloc (nmemb, size);
134 else
136 __malloc_lock ();
137 res = dlcalloc (nmemb, size);
138 __malloc_unlock ();
140 malloc_printf ("(%ld, %ld) = %p, called by %p", nmemb, size, res,
141 caller_return_address ());
142 return res;
145 extern "C" int
146 posix_memalign (void **memptr, size_t alignment, size_t bytes)
148 save_errno save;
150 void *res;
151 if (!use_internal)
152 return user_data->posix_memalign (memptr, alignment, bytes);
153 if ((alignment & (alignment - 1)) != 0)
154 return EINVAL;
155 __malloc_lock ();
156 res = dlmemalign (alignment, bytes);
157 __malloc_unlock ();
158 if (!res)
159 return ENOMEM;
160 *memptr = res;
161 return 0;
164 extern "C" void *
165 memalign (size_t alignment, size_t bytes)
167 void *res;
168 if (!use_internal)
170 set_errno (ENOSYS);
171 res = NULL;
173 else
175 __malloc_lock ();
176 res = dlmemalign (alignment, bytes);
177 __malloc_unlock ();
180 return res;
183 extern "C" void *
184 valloc (size_t bytes)
186 void *res;
187 if (!use_internal)
189 set_errno (ENOSYS);
190 res = NULL;
192 else
194 __malloc_lock ();
195 res = dlvalloc (bytes);
196 __malloc_unlock ();
199 return res;
202 extern "C" size_t
203 malloc_usable_size (void *p)
205 size_t res;
206 if (!use_internal)
208 set_errno (ENOSYS);
209 res = 0;
211 else
213 __malloc_lock ();
214 res = dlmalloc_usable_size (p);
215 __malloc_unlock ();
218 return res;
221 extern "C" int
222 malloc_trim (size_t pad)
224 size_t res;
225 if (!use_internal)
227 set_errno (ENOSYS);
228 res = 0;
230 else
232 __malloc_lock ();
233 res = dlmalloc_trim (pad);
234 __malloc_unlock ();
237 return res;
240 extern "C" int
241 mallopt (int p, int v)
243 int res;
244 if (!use_internal)
246 set_errno (ENOSYS);
247 res = 0;
249 else
251 __malloc_lock ();
252 res = dlmallopt (p, v);
253 __malloc_unlock ();
256 return res;
259 extern "C" void
260 malloc_stats ()
262 if (!use_internal)
263 set_errno (ENOSYS);
264 else
266 __malloc_lock ();
267 dlmalloc_stats ();
268 __malloc_unlock ();
272 extern "C" struct mallinfo
273 mallinfo ()
275 struct mallinfo m;
276 if (!use_internal)
278 memset (&m, 0, sizeof m);
279 set_errno (ENOSYS);
281 else
283 __malloc_lock ();
284 m = dlmallinfo ();
285 __malloc_unlock ();
288 return m;
291 extern "C" char *
292 strdup (const char *s)
294 char *p;
295 size_t len = strlen (s) + 1;
296 if ((p = (char *) malloc (len)) != NULL)
297 memcpy (p, s, len);
298 return p;
301 /* We use a SRW lock to lock access to the malloc data structures. This
302 permits malloc to be called from different threads. Note that it does
303 not make malloc reentrant, and it does not permit a signal handler to
304 call malloc. The malloc code in newlib will call __malloc_lock and
305 __malloc_unlock at appropriate times. */
307 SRWLOCK NO_COPY mallock = SRWLOCK_INIT;
309 void
310 malloc_init ()
312 /* Check if malloc is provided by application. If so, redirect all
313 calls to malloc/free/realloc to application provided. This may
314 happen if some other dll calls cygwin's malloc, but main code provides
315 its own malloc */
316 if (!internal_malloc_determined)
318 extern void *_sigfe_malloc;
319 /* Decide if we are using our own version of malloc by testing the import
320 address from user_data. */
321 use_internal = user_data->malloc == malloc
322 || import_address ((void *) user_data->malloc)
323 == &_sigfe_malloc;
324 malloc_printf ("using %s malloc", use_internal ? "internal" : "external");
325 internal_malloc_determined = true;
329 extern "C" void
330 __set_ENOMEM ()
332 set_errno (ENOMEM);