~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/msvcrt/heap.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * msvcrt.dll heap functions
  3  *
  4  * Copyright 2000 Jon Griffiths
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  *
 20  * Note: Win32 heap operations are MT safe. We only lock the new
 21  *       handler and non atomic heap operations
 22  */
 23 
 24 #include "msvcrt.h"
 25 #include "mtdll.h"
 26 #include "wine/debug.h"
 27 
 28 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
 29 
 30 /* MT */
 31 #define LOCK_HEAP   _mlock( _HEAP_LOCK )
 32 #define UNLOCK_HEAP _munlock( _HEAP_LOCK )
 33 
 34 /* _aligned */
 35 #define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
 36                                ~(sizeof(void *) - 1)))
 37 #define ALIGN_PTR(ptr, alignment, offset) ((void *) \
 38     ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \
 39       ~(alignment - 1)) - offset))
 40 
 41 
 42 typedef void (*MSVCRT_new_handler_func)(MSVCRT_size_t size);
 43 
 44 static MSVCRT_new_handler_func MSVCRT_new_handler;
 45 static int MSVCRT_new_mode;
 46 
 47 /* FIXME - According to documentation it should be 8*1024, at runtime it returns 16 */ 
 48 static unsigned int MSVCRT_amblksiz = 16;
 49 /* FIXME - According to documentation it should be 480 bytes, at runtime default is 0 */
 50 static MSVCRT_size_t MSVCRT_sbh_threshold = 0;
 51 
 52 /*********************************************************************
 53  *              ??2@YAPAXI@Z (MSVCRT.@)
 54  */
 55 void* CDECL MSVCRT_operator_new(MSVCRT_size_t size)
 56 {
 57   void *retval = HeapAlloc(GetProcessHeap(), 0, size);
 58   TRACE("(%ld) returning %p\n", size, retval);
 59   if(retval) return retval;
 60   LOCK_HEAP;
 61   if(MSVCRT_new_handler)
 62     (*MSVCRT_new_handler)(size);
 63   UNLOCK_HEAP;
 64   return retval;
 65 }
 66 
 67 /*********************************************************************
 68  *              ??3@YAXPAX@Z (MSVCRT.@)
 69  */
 70 void CDECL MSVCRT_operator_delete(void *mem)
 71 {
 72   TRACE("(%p)\n", mem);
 73   HeapFree(GetProcessHeap(), 0, mem);
 74 }
 75 
 76 
 77 /*********************************************************************
 78  *              ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@)
 79  */
 80 MSVCRT_new_handler_func CDECL MSVCRT__query_new_handler(void)
 81 {
 82   return MSVCRT_new_handler;
 83 }
 84 
 85 
 86 /*********************************************************************
 87  *              ?_query_new_mode@@YAHXZ (MSVCRT.@)
 88  */
 89 int CDECL MSVCRT__query_new_mode(void)
 90 {
 91   return MSVCRT_new_mode;
 92 }
 93 
 94 /*********************************************************************
 95  *              ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@)
 96  */
 97 MSVCRT_new_handler_func CDECL MSVCRT__set_new_handler(MSVCRT_new_handler_func func)
 98 {
 99   MSVCRT_new_handler_func old_handler;
100   LOCK_HEAP;
101   old_handler = MSVCRT_new_handler;
102   MSVCRT_new_handler = func;
103   UNLOCK_HEAP;
104   return old_handler;
105 }
106 
107 /*********************************************************************
108  *              ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
109  */
110 MSVCRT_new_handler_func CDECL MSVCRT_set_new_handler(void *func)
111 {
112   TRACE("(%p)\n",func);
113   MSVCRT__set_new_handler(NULL);
114   return NULL;
115 }
116 
117 /*********************************************************************
118  *              ?_set_new_mode@@YAHH@Z (MSVCRT.@)
119  */
120 int CDECL MSVCRT__set_new_mode(int mode)
121 {
122   int old_mode;
123   LOCK_HEAP;
124   old_mode = MSVCRT_new_mode;
125   MSVCRT_new_mode = mode;
126   UNLOCK_HEAP;
127   return old_mode;
128 }
129 
130 /*********************************************************************
131  *              _callnewh (MSVCRT.@)
132  */
133 int CDECL _callnewh(MSVCRT_size_t size)
134 {
135   if(MSVCRT_new_handler)
136     (*MSVCRT_new_handler)(size);
137   return 0;
138 }
139 
140 /*********************************************************************
141  *              _expand (MSVCRT.@)
142  */
143 void* CDECL _expand(void* mem, MSVCRT_size_t size)
144 {
145   return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size);
146 }
147 
148 /*********************************************************************
149  *              _heapchk (MSVCRT.@)
150  */
151 int CDECL _heapchk(void)
152 {
153   if (!HeapValidate( GetProcessHeap(), 0, NULL))
154   {
155     msvcrt_set_errno(GetLastError());
156     return MSVCRT__HEAPBADNODE;
157   }
158   return MSVCRT__HEAPOK;
159 }
160 
161 /*********************************************************************
162  *              _heapmin (MSVCRT.@)
163  */
164 int CDECL _heapmin(void)
165 {
166   if (!HeapCompact( GetProcessHeap(), 0 ))
167   {
168     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
169       msvcrt_set_errno(GetLastError());
170     return -1;
171   }
172   return 0;
173 }
174 
175 /*********************************************************************
176  *              _heapwalk (MSVCRT.@)
177  */
178 int CDECL _heapwalk(struct MSVCRT__heapinfo* next)
179 {
180   PROCESS_HEAP_ENTRY phe;
181 
182   LOCK_HEAP;
183   phe.lpData = next->_pentry;
184   phe.cbData = next->_size;
185   phe.wFlags = next->_useflag == MSVCRT__USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0;
186 
187   if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY &&
188       !HeapValidate( GetProcessHeap(), 0, phe.lpData ))
189   {
190     UNLOCK_HEAP;
191     msvcrt_set_errno(GetLastError());
192     return MSVCRT__HEAPBADNODE;
193   }
194 
195   do
196   {
197     if (!HeapWalk( GetProcessHeap(), &phe ))
198     {
199       UNLOCK_HEAP;
200       if (GetLastError() == ERROR_NO_MORE_ITEMS)
201          return MSVCRT__HEAPEND;
202       msvcrt_set_errno(GetLastError());
203       if (!phe.lpData)
204         return MSVCRT__HEAPBADBEGIN;
205       return MSVCRT__HEAPBADNODE;
206     }
207   } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE));
208 
209   UNLOCK_HEAP;
210   next->_pentry = phe.lpData;
211   next->_size = phe.cbData;
212   next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? MSVCRT__USEDENTRY : MSVCRT__FREEENTRY;
213   return MSVCRT__HEAPOK;
214 }
215 
216 /*********************************************************************
217  *              _heapset (MSVCRT.@)
218  */
219 int CDECL _heapset(unsigned int value)
220 {
221   int retval;
222   struct MSVCRT__heapinfo heap;
223 
224   memset( &heap, 0, sizeof(heap) );
225   LOCK_HEAP;
226   while ((retval = _heapwalk(&heap)) == MSVCRT__HEAPOK)
227   {
228     if (heap._useflag == MSVCRT__FREEENTRY)
229       memset(heap._pentry, value, heap._size);
230   }
231   UNLOCK_HEAP;
232   return retval == MSVCRT__HEAPEND? MSVCRT__HEAPOK : retval;
233 }
234 
235 /*********************************************************************
236  *              _heapadd (MSVCRT.@)
237  */
238 int CDECL _heapadd(void* mem, MSVCRT_size_t size)
239 {
240   TRACE("(%p,%ld) unsupported in Win32\n", mem,size);
241   *MSVCRT__errno() = MSVCRT_ENOSYS;
242   return -1;
243 }
244 
245 /*********************************************************************
246  *              _msize (MSVCRT.@)
247  */
248 MSVCRT_size_t CDECL _msize(void* mem)
249 {
250   MSVCRT_size_t size = HeapSize(GetProcessHeap(),0,mem);
251   if (size == ~(MSVCRT_size_t)0)
252   {
253     WARN(":Probably called with non wine-allocated memory, ret = -1\n");
254     /* At least the Win32 crtdll/msvcrt also return -1 in this case */
255   }
256   return size;
257 }
258 
259 /*********************************************************************
260  *              calloc (MSVCRT.@)
261  */
262 void* CDECL MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count)
263 {
264   return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
265 }
266 
267 /*********************************************************************
268  *              free (MSVCRT.@)
269  */
270 void CDECL MSVCRT_free(void* ptr)
271 {
272   HeapFree(GetProcessHeap(),0,ptr);
273 }
274 
275 /*********************************************************************
276  *                  malloc (MSVCRT.@)
277  */
278 void* CDECL MSVCRT_malloc(MSVCRT_size_t size)
279 {
280   void *ret = HeapAlloc(GetProcessHeap(),0,size);
281   if (!ret)
282       *MSVCRT__errno() = MSVCRT_ENOMEM;
283   return ret;
284 }
285 
286 /*********************************************************************
287  *              realloc (MSVCRT.@)
288  */
289 void* CDECL MSVCRT_realloc(void* ptr, MSVCRT_size_t size)
290 {
291   if (!ptr) return MSVCRT_malloc(size);
292   if (size) return HeapReAlloc(GetProcessHeap(), 0, ptr, size);
293   MSVCRT_free(ptr);
294   return NULL;
295 }
296 
297 /*********************************************************************
298  *              __p__amblksiz (MSVCRT.@)
299  */
300 unsigned int* CDECL __p__amblksiz(void)
301 {
302   return &MSVCRT_amblksiz;
303 }
304 
305 /*********************************************************************
306  *              _get_sbh_threshold (MSVCRT.@)
307  */
308 MSVCRT_size_t CDECL _get_sbh_threshold(void)
309 {
310   return MSVCRT_sbh_threshold;
311 }
312 
313 /*********************************************************************
314  *              _set_sbh_threshold (MSVCRT.@)
315  */
316 int CDECL _set_sbh_threshold(MSVCRT_size_t threshold)
317 {
318   if(threshold > 1016)
319      return 0;
320   else
321      MSVCRT_sbh_threshold = threshold;
322   return 1;
323 }
324 
325 /*********************************************************************
326  *              _aligned_free (MSVCRT.@)
327  */
328 void CDECL _aligned_free(void *memblock)
329 {
330     TRACE("(%p)\n", memblock);
331 
332     if (memblock)
333     {
334         void **saved = SAVED_PTR(memblock);
335         MSVCRT_free(*saved);
336     }
337 }
338 
339 /*********************************************************************
340  *              _aligned_offset_malloc (MSVCRT.@)
341  */
342 void * CDECL _aligned_offset_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment, MSVCRT_size_t offset)
343 {
344     void *memblock, *temp, **saved;
345     TRACE("(%lu, %lu, %lu)\n", size, alignment, offset);
346 
347     /* alignment must be a power of 2 */
348     if ((alignment & (alignment - 1)) != 0)
349     {
350         *MSVCRT__errno() = MSVCRT_EINVAL;
351         return NULL;
352     }
353 
354     /* offset must be less than size */
355     if (offset >= size)
356     {
357         *MSVCRT__errno() = MSVCRT_EINVAL;
358         return NULL;
359     }
360 
361     /* don't align to less than void pointer size */
362     if (alignment < sizeof(void *))
363         alignment = sizeof(void *);
364 
365     /* allocate enough space for void pointer and alignment */
366     temp = MSVCRT_malloc(size + alignment + sizeof(void *));
367 
368     if (!temp)
369         return NULL;
370 
371     /* adjust pointer for proper alignment and offset */
372     memblock = ALIGN_PTR(temp, alignment, offset);
373 
374     /* Save the real allocation address below returned address */
375     /* so it can be found later to free. */
376     saved = SAVED_PTR(memblock);
377     *saved = temp;
378 
379     return memblock;
380 }
381 
382 /*********************************************************************
383  *              _aligned_malloc (MSVCRT.@)
384  */
385 void * CDECL _aligned_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment)
386 {
387     TRACE("(%lu, %lu)\n", size, alignment);
388     return _aligned_offset_malloc(size, alignment, 0);
389 }
390 
391 /*********************************************************************
392  *              _aligned_offset_realloc (MSVCRT.@)
393  */
394 void * CDECL _aligned_offset_realloc(void *memblock, MSVCRT_size_t size,
395                                      MSVCRT_size_t alignment, MSVCRT_size_t offset)
396 {
397     void * temp, **saved;
398     MSVCRT_size_t old_padding, new_padding, old_size;
399     TRACE("(%p, %lu, %lu, %lu)\n", memblock, size, alignment, offset);
400 
401     if (!memblock)
402         return _aligned_offset_malloc(size, alignment, offset);
403 
404     /* alignment must be a power of 2 */
405     if ((alignment & (alignment - 1)) != 0)
406     {
407         *MSVCRT__errno() = MSVCRT_EINVAL;
408         return NULL;
409     }
410 
411     /* offset must be less than size */
412     if (offset >= size)
413     {
414         *MSVCRT__errno() = MSVCRT_EINVAL;
415         return NULL;
416     }
417 
418     if (size == 0)
419     {
420         _aligned_free(memblock);
421         return NULL;
422     }
423 
424     /* don't align to less than void pointer size */
425     if (alignment < sizeof(void *))
426         alignment = sizeof(void *);
427 
428     /* make sure alignment and offset didn't change */
429     saved = SAVED_PTR(memblock);
430     if (memblock != ALIGN_PTR(*saved, alignment, offset))
431     {
432         *MSVCRT__errno() = MSVCRT_EINVAL;
433         return NULL;
434     }
435 
436     old_padding = (char *)memblock - (char *)*saved;
437 
438     /* Get previous size of block */
439     old_size = _msize(*saved);
440     if (old_size == -1)
441     {
442         /* It seems this function was called with an invalid pointer. Bail out. */
443         return NULL;
444     }
445 
446     /* Adjust old_size to get amount of actual data in old block. */
447     if (old_size < old_padding)
448     {
449         /* Shouldn't happen. Something's weird, so bail out. */
450         return NULL;
451     }
452     old_size -= old_padding;
453 
454     temp = MSVCRT_realloc(*saved, size + alignment + sizeof(void *));
455 
456     if (!temp)
457         return NULL;
458 
459     /* adjust pointer for proper alignment and offset */
460     memblock = ALIGN_PTR(temp, alignment, offset);
461 
462     /* Save the real allocation address below returned address */
463     /* so it can be found later to free. */
464     saved = SAVED_PTR(memblock);
465 
466     new_padding = (char *)memblock - (char *)temp;
467 
468 /*
469    Memory layout of old block is as follows:
470    +-------+---------------------+-+--------------------------+-----------+
471    |  ...  | "old_padding" bytes | | ... "old_size" bytes ... |    ...    |
472    +-------+---------------------+-+--------------------------+-----------+
473            ^                     ^ ^
474            |                     | |
475         *saved               saved memblock
476 
477    Memory layout of new block is as follows:
478    +-------+-----------------------------+-+----------------------+-------+
479    |  ...  |    "new_padding" bytes      | | ... "size" bytes ... |  ...  |
480    +-------+-----------------------------+-+----------------------+-------+
481            ^                             ^ ^
482            |                             | |
483           temp                       saved memblock
484 
485    However, in the new block, actual data is still written as follows
486    (because it was copied by MSVCRT_realloc):
487    +-------+---------------------+--------------------------------+-------+
488    |  ...  | "old_padding" bytes |   ... "old_size" bytes ...     |  ...  |
489    +-------+---------------------+--------------------------------+-------+
490            ^                             ^ ^
491            |                             | |
492           temp                       saved memblock
493 
494    Therefore, min(old_size,size) bytes of actual data have to be moved
495    from the offset they were at in the old block (temp + old_padding),
496    to the offset they have to be in the new block (temp + new_padding == memblock).
497 */
498     if (new_padding != old_padding)
499         memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
500 
501     *saved = temp;
502 
503     return memblock;
504 }
505 
506 /*********************************************************************
507  *              _aligned_realloc (MSVCRT.@)
508  */
509 void * CDECL _aligned_realloc(void *memblock, MSVCRT_size_t size, MSVCRT_size_t alignment)
510 {
511     TRACE("(%p, %lu, %lu)\n", memblock, size, alignment);
512     return _aligned_offset_realloc(memblock, size, alignment, 0);
513 }
514 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.