xref: /reactos/sdk/lib/crt/wine/heap.c (revision 1d6ec855)
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 <precomp.h>
25 #include <malloc.h>
26 
27 #define MSVCRT_size_t size_t
28 #define MSVCRT_intptr_t intptr_t
29 #define MSVCRT_wchar_t wchar_t
30 #define MSVCRT__HEAPBADNODE _HEAPBADNODE
31 #define MSVCRT__HEAPOK _HEAPOK
32 #define MSVCRT__HEAPEND _HEAPEND
33 #define MSVCRT__FREEENTRY _FREEENTRY
34 #define MSVCRT__USEDENTRY _USEDENTRY
35 #define MSVCRT__HEAPBADBEGIN _HEAPBADBEGIN
36 #define MSVCRT_EINVAL EINVAL
37 #define MSVCRT_ENOSYS ENOSYS
38 #define MSVCRT_ENOMEM ENOMEM
39 #define MSVCRT_ERANGE ERANGE
40 #define MSVCRT__TRUNCATE _TRUNCATE
41 #define MSVCRT__heapinfo _heapinfo
42 #define MSVCRT__errno _errno
43 #define MSVCRT_calloc calloc
44 #define MSVCRT_malloc malloc
45 #define MSVCRT_realloc realloc
46 #define MSVCRT_free free
47 #define MSVCRT_memcpy_s memcpy_s
48 #define MSVCRT_memmove_s memmove_s
49 #define MSVCRT_strncpy_s strncpy_s
50 #define msvcrt_set_errno _dosmaperr
51 
52 /* MT */
53 #define LOCK_HEAP   _mlock( _HEAP_LOCK )
54 #define UNLOCK_HEAP _munlock( _HEAP_LOCK )
55 
56 /* _aligned */
57 #define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
58                                ~(sizeof(void *) - 1)))
59 #define ALIGN_PTR(ptr, alignment, offset) ((void *) \
60     ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \
61       ~(alignment - 1)) - offset))
62 
63 #define SB_HEAP_ALIGN 16
64 
65 static HANDLE heap, sb_heap;
66 
67 typedef int (CDECL *MSVCRT_new_handler_func)(MSVCRT_size_t size);
68 
69 static MSVCRT_new_handler_func MSVCRT_new_handler;
70 static int MSVCRT_new_mode;
71 
72 /* FIXME - According to documentation it should be 8*1024, at runtime it returns 16 */
73 static unsigned int MSVCRT_amblksiz = 16;
74 /* FIXME - According to documentation it should be 480 bytes, at runtime default is 0 */
75 static MSVCRT_size_t MSVCRT_sbh_threshold = 0;
76 
77 static void* msvcrt_heap_alloc(DWORD flags, MSVCRT_size_t size)
78 {
79     if(size < MSVCRT_sbh_threshold)
80     {
81         void *memblock, *temp, **saved;
82 
83         temp = HeapAlloc(sb_heap, flags, size+sizeof(void*)+SB_HEAP_ALIGN);
84         if(!temp) return NULL;
85 
86         memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
87         saved = SAVED_PTR(memblock);
88         *saved = temp;
89         return memblock;
90     }
91 
92     return HeapAlloc(heap, flags, size);
93 }
94 
95 static void* msvcrt_heap_realloc(DWORD flags, void *ptr, MSVCRT_size_t size)
96 {
97     if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
98     {
99         /* TODO: move data to normal heap if it exceeds sbh_threshold limit */
100         void *memblock, *temp, **saved;
101         MSVCRT_size_t old_padding, new_padding, old_size;
102 
103         saved = SAVED_PTR(ptr);
104         old_padding = (char*)ptr - (char*)*saved;
105         old_size = HeapSize(sb_heap, 0, *saved);
106         if(old_size == -1)
107             return NULL;
108         old_size -= old_padding;
109 
110         temp = HeapReAlloc(sb_heap, flags, *saved, size+sizeof(void*)+SB_HEAP_ALIGN);
111         if(!temp) return NULL;
112 
113         memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
114         saved = SAVED_PTR(memblock);
115         new_padding = (char*)memblock - (char*)temp;
116 
117         if(new_padding != old_padding)
118             memmove(memblock, (char*)temp+old_padding, old_size>size ? size : old_size);
119 
120         *saved = temp;
121         return memblock;
122     }
123 
124     return HeapReAlloc(heap, flags, ptr, size);
125 }
126 
127 static BOOL msvcrt_heap_free(void *ptr)
128 {
129     if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
130     {
131         void **saved = SAVED_PTR(ptr);
132         return HeapFree(sb_heap, 0, *saved);
133     }
134 
135     return HeapFree(heap, 0, ptr);
136 }
137 
138 static MSVCRT_size_t msvcrt_heap_size(void *ptr)
139 {
140     if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
141     {
142         void **saved = SAVED_PTR(ptr);
143         return HeapSize(sb_heap, 0, *saved);
144     }
145 
146     return HeapSize(heap, 0, ptr);
147 }
148 
149 /*********************************************************************
150  *		??2@YAPAXI@Z (MSVCRT.@)
151  */
152 void* CDECL MSVCRT_operator_new(MSVCRT_size_t size)
153 {
154   void *retval;
155   int freed;
156   MSVCRT_new_handler_func handler;
157 
158   do
159   {
160     retval = msvcrt_heap_alloc(0, size);
161     if(retval)
162     {
163       TRACE("(%ld) returning %p\n", size, retval);
164       return retval;
165     }
166 
167     LOCK_HEAP;
168     handler = MSVCRT_new_handler;
169     if(handler)
170       freed = (*handler)(size);
171     else
172       freed = 0;
173     UNLOCK_HEAP;
174   } while(freed);
175 
176   TRACE("(%ld) out of memory\n", size);
177 #if _MSVCR_VER >= 80
178   throw_bad_alloc("bad allocation");
179 #endif
180   return NULL;
181 }
182 
183 
184 /*********************************************************************
185  *		??2@YAPAXIHPBDH@Z (MSVCRT.@)
186  */
187 void* CDECL MSVCRT_operator_new_dbg(MSVCRT_size_t size, int type, const char *file, int line)
188 {
189     return MSVCRT_operator_new( size );
190 }
191 
192 
193 /*********************************************************************
194  *		??3@YAXPAX@Z (MSVCRT.@)
195  */
196 void CDECL MSVCRT_operator_delete(void *mem)
197 {
198   TRACE("(%p)\n", mem);
199   msvcrt_heap_free(mem);
200 }
201 
202 
203 /*********************************************************************
204  *		?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@)
205  */
206 MSVCRT_new_handler_func CDECL MSVCRT__query_new_handler(void)
207 {
208   return MSVCRT_new_handler;
209 }
210 
211 
212 /*********************************************************************
213  *		?_query_new_mode@@YAHXZ (MSVCRT.@)
214  */
215 int CDECL MSVCRT__query_new_mode(void)
216 {
217   return MSVCRT_new_mode;
218 }
219 
220 /*********************************************************************
221  *		?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@)
222  */
223 MSVCRT_new_handler_func CDECL MSVCRT__set_new_handler(MSVCRT_new_handler_func func)
224 {
225   MSVCRT_new_handler_func old_handler;
226   LOCK_HEAP;
227   old_handler = MSVCRT_new_handler;
228   MSVCRT_new_handler = func;
229   UNLOCK_HEAP;
230   return old_handler;
231 }
232 
233 /*********************************************************************
234  *		?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
235  */
236 MSVCRT_new_handler_func CDECL MSVCRT_set_new_handler(void *func)
237 {
238   TRACE("(%p)\n",func);
239   MSVCRT__set_new_handler(NULL);
240   return NULL;
241 }
242 
243 /*********************************************************************
244  *		?_set_new_mode@@YAHH@Z (MSVCRT.@)
245  */
246 int CDECL MSVCRT__set_new_mode(int mode)
247 {
248   int old_mode;
249   LOCK_HEAP;
250   old_mode = MSVCRT_new_mode;
251   MSVCRT_new_mode = mode;
252   UNLOCK_HEAP;
253   return old_mode;
254 }
255 
256 /*********************************************************************
257  *		_callnewh (MSVCRT.@)
258  */
259 int CDECL _callnewh(MSVCRT_size_t size)
260 {
261   int ret = 0;
262   MSVCRT_new_handler_func handler = MSVCRT_new_handler;
263   if(handler)
264     ret = (*handler)(size) ? 1 : 0;
265   return ret;
266 }
267 
268 /*********************************************************************
269  *		_expand (MSVCRT.@)
270  */
271 void* CDECL _expand(void* mem, MSVCRT_size_t size)
272 {
273   return msvcrt_heap_realloc(HEAP_REALLOC_IN_PLACE_ONLY, mem, size);
274 }
275 
276 /*********************************************************************
277  *		_heapchk (MSVCRT.@)
278  */
279 int CDECL _heapchk(void)
280 {
281   if (!HeapValidate(heap, 0, NULL) ||
282           (sb_heap && !HeapValidate(sb_heap, 0, NULL)))
283   {
284     msvcrt_set_errno(GetLastError());
285     return MSVCRT__HEAPBADNODE;
286   }
287   return MSVCRT__HEAPOK;
288 }
289 
290 /*********************************************************************
291  *		_heapmin (MSVCRT.@)
292  */
293 int CDECL _heapmin(void)
294 {
295   if (!HeapCompact( heap, 0 ) ||
296           (sb_heap && !HeapCompact( sb_heap, 0 )))
297   {
298     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
299       msvcrt_set_errno(GetLastError());
300     return -1;
301   }
302   return 0;
303 }
304 
305 /*********************************************************************
306  *		_heapwalk (MSVCRT.@)
307  */
308 int CDECL _heapwalk(struct MSVCRT__heapinfo* next)
309 {
310   PROCESS_HEAP_ENTRY phe;
311 
312   if (sb_heap)
313       FIXME("small blocks heap not supported\n");
314 
315   LOCK_HEAP;
316   phe.lpData = next->_pentry;
317   phe.cbData = (DWORD)next->_size;
318   phe.wFlags = next->_useflag == MSVCRT__USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0;
319 
320   if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY &&
321       !HeapValidate( heap, 0, phe.lpData ))
322   {
323     UNLOCK_HEAP;
324     msvcrt_set_errno(GetLastError());
325     return MSVCRT__HEAPBADNODE;
326   }
327 
328   do
329   {
330     if (!HeapWalk( heap, &phe ))
331     {
332       UNLOCK_HEAP;
333       if (GetLastError() == ERROR_NO_MORE_ITEMS)
334          return MSVCRT__HEAPEND;
335       msvcrt_set_errno(GetLastError());
336       if (!phe.lpData)
337         return MSVCRT__HEAPBADBEGIN;
338       return MSVCRT__HEAPBADNODE;
339     }
340   } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE));
341 
342   UNLOCK_HEAP;
343   next->_pentry = phe.lpData;
344   next->_size = phe.cbData;
345   next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? MSVCRT__USEDENTRY : MSVCRT__FREEENTRY;
346   return MSVCRT__HEAPOK;
347 }
348 
349 /*********************************************************************
350  *		_heapset (MSVCRT.@)
351  */
352 int CDECL _heapset(unsigned int value)
353 {
354   int retval;
355   struct MSVCRT__heapinfo heap;
356 
357   memset( &heap, 0, sizeof(heap) );
358   LOCK_HEAP;
359   while ((retval = _heapwalk(&heap)) == MSVCRT__HEAPOK)
360   {
361     if (heap._useflag == MSVCRT__FREEENTRY)
362       memset(heap._pentry, value, heap._size);
363   }
364   UNLOCK_HEAP;
365   return retval == MSVCRT__HEAPEND? MSVCRT__HEAPOK : retval;
366 }
367 
368 /*********************************************************************
369  *		_heapadd (MSVCRT.@)
370  */
371 int CDECL _heapadd(void* mem, MSVCRT_size_t size)
372 {
373   TRACE("(%p,%ld) unsupported in Win32\n", mem,size);
374   *MSVCRT__errno() = MSVCRT_ENOSYS;
375   return -1;
376 }
377 
378 /*********************************************************************
379  *		_get_heap_handle (MSVCRT.@)
380  */
381 MSVCRT_intptr_t CDECL _get_heap_handle(void)
382 {
383     return (MSVCRT_intptr_t)heap;
384 }
385 
386 /*********************************************************************
387  *		_msize (MSVCRT.@)
388  */
389 MSVCRT_size_t CDECL _msize(void* mem)
390 {
391   MSVCRT_size_t size = msvcrt_heap_size(mem);
392   if (size == ~(MSVCRT_size_t)0)
393   {
394     WARN(":Probably called with non wine-allocated memory, ret = -1\n");
395     /* At least the Win32 crtdll/msvcrt also return -1 in this case */
396   }
397   return size;
398 }
399 
400 /*********************************************************************
401  * _aligned_msize (MSVCR100.@)
402  */
403 size_t CDECL _aligned_msize(void *p, MSVCRT_size_t alignment, MSVCRT_size_t offset)
404 {
405     void **alloc_ptr;
406 
407     if(!MSVCRT_CHECK_PMT(p)) return -1;
408 
409     if(alignment < sizeof(void*))
410         alignment = sizeof(void*);
411 
412     alloc_ptr = SAVED_PTR(p);
413     return _msize(*alloc_ptr)-alignment-sizeof(void*);
414 }
415 
416 /*********************************************************************
417  *		calloc (MSVCRT.@)
418  */
419 void* CDECL MSVCRT_calloc(MSVCRT_size_t count, MSVCRT_size_t size)
420 {
421   MSVCRT_size_t bytes = count*size;
422 
423   if (size && bytes / size != count)
424   {
425     *MSVCRT__errno() = MSVCRT_ENOMEM;
426     return NULL;
427   }
428 
429   return msvcrt_heap_alloc(HEAP_ZERO_MEMORY, bytes);
430 }
431 
432 /*********************************************************************
433  *		free (MSVCRT.@)
434  */
435 void CDECL MSVCRT_free(void* ptr)
436 {
437   msvcrt_heap_free(ptr);
438 }
439 
440 /*********************************************************************
441  *                  malloc (MSVCRT.@)
442  */
443 void* CDECL MSVCRT_malloc(MSVCRT_size_t size)
444 {
445   void *ret = msvcrt_heap_alloc(0, size);
446   if (!ret)
447       *MSVCRT__errno() = MSVCRT_ENOMEM;
448   return ret;
449 }
450 
451 /*********************************************************************
452  *		realloc (MSVCRT.@)
453  */
454 void* CDECL MSVCRT_realloc(void* ptr, MSVCRT_size_t size)
455 {
456   if (!ptr) return MSVCRT_malloc(size);
457   if (size) return msvcrt_heap_realloc(0, ptr, size);
458   MSVCRT_free(ptr);
459   return NULL;
460 }
461 
462 /*********************************************************************
463  * _recalloc (MSVCR100.@)
464  */
465 void* CDECL _recalloc(void *mem, MSVCRT_size_t num, MSVCRT_size_t size)
466 {
467     MSVCRT_size_t old_size;
468     void *ret;
469 
470     if(!mem)
471         return MSVCRT_calloc(num, size);
472 
473     size = num*size;
474     old_size = _msize(mem);
475 
476     ret = MSVCRT_realloc(mem, size);
477     if(!ret) {
478         *MSVCRT__errno() = MSVCRT_ENOMEM;
479         return NULL;
480     }
481 
482     if(size>old_size)
483         memset((BYTE*)ret+old_size, 0, size-old_size);
484     return ret;
485 }
486 
487 /*********************************************************************
488  *		__p__amblksiz (MSVCRT.@)
489  */
490 unsigned int* CDECL __p__amblksiz(void)
491 {
492   return &MSVCRT_amblksiz;
493 }
494 
495 /*********************************************************************
496  *		_get_sbh_threshold (MSVCRT.@)
497  */
498 MSVCRT_size_t CDECL _get_sbh_threshold(void)
499 {
500   return MSVCRT_sbh_threshold;
501 }
502 
503 /*********************************************************************
504  *		_set_sbh_threshold (MSVCRT.@)
505  */
506 int CDECL _set_sbh_threshold(MSVCRT_size_t threshold)
507 {
508 #ifdef _WIN64
509   return 0;
510 #else
511   if(threshold > 1016)
512      return 0;
513 
514   if(!sb_heap)
515   {
516       sb_heap = HeapCreate(0, 0, 0);
517       if(!sb_heap)
518           return 0;
519   }
520 
521   MSVCRT_sbh_threshold = (threshold+0xf) & ~0xf;
522   return 1;
523 #endif
524 }
525 
526 /*********************************************************************
527  *		_aligned_free (MSVCRT.@)
528  */
529 void CDECL _aligned_free(void *memblock)
530 {
531     TRACE("(%p)\n", memblock);
532 
533     if (memblock)
534     {
535         void **saved = SAVED_PTR(memblock);
536         MSVCRT_free(*saved);
537     }
538 }
539 
540 /*********************************************************************
541  *		_aligned_offset_malloc (MSVCRT.@)
542  */
543 void * CDECL _aligned_offset_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment, MSVCRT_size_t offset)
544 {
545     void *memblock, *temp, **saved;
546     TRACE("(%lu, %lu, %lu)\n", size, alignment, offset);
547 
548     /* alignment must be a power of 2 */
549     if ((alignment & (alignment - 1)) != 0)
550     {
551         *MSVCRT__errno() = MSVCRT_EINVAL;
552         return NULL;
553     }
554 
555     /* offset must be less than size */
556     if (offset && offset >= size)
557     {
558         *MSVCRT__errno() = MSVCRT_EINVAL;
559         return NULL;
560     }
561 
562     /* don't align to less than void pointer size */
563     if (alignment < sizeof(void *))
564         alignment = sizeof(void *);
565 
566     /* allocate enough space for void pointer and alignment */
567     temp = MSVCRT_malloc(size + alignment + sizeof(void *));
568 
569     if (!temp)
570         return NULL;
571 
572     /* adjust pointer for proper alignment and offset */
573     memblock = ALIGN_PTR(temp, alignment, offset);
574 
575     /* Save the real allocation address below returned address */
576     /* so it can be found later to free. */
577     saved = SAVED_PTR(memblock);
578     *saved = temp;
579 
580     return memblock;
581 }
582 
583 /*********************************************************************
584  *		_aligned_malloc (MSVCRT.@)
585  */
586 void * CDECL _aligned_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment)
587 {
588     TRACE("(%lu, %lu)\n", size, alignment);
589     return _aligned_offset_malloc(size, alignment, 0);
590 }
591 
592 /*********************************************************************
593  *		_aligned_offset_realloc (MSVCRT.@)
594  */
595 void * CDECL _aligned_offset_realloc(void *memblock, MSVCRT_size_t size,
596                                      MSVCRT_size_t alignment, MSVCRT_size_t offset)
597 {
598     void * temp, **saved;
599     MSVCRT_size_t old_padding, new_padding, old_size;
600     TRACE("(%p, %lu, %lu, %lu)\n", memblock, size, alignment, offset);
601 
602     if (!memblock)
603         return _aligned_offset_malloc(size, alignment, offset);
604 
605     /* alignment must be a power of 2 */
606     if ((alignment & (alignment - 1)) != 0)
607     {
608         *MSVCRT__errno() = MSVCRT_EINVAL;
609         return NULL;
610     }
611 
612     /* offset must be less than size */
613     if (offset >= size)
614     {
615         *MSVCRT__errno() = MSVCRT_EINVAL;
616         return NULL;
617     }
618 
619     if (size == 0)
620     {
621         _aligned_free(memblock);
622         return NULL;
623     }
624 
625     /* don't align to less than void pointer size */
626     if (alignment < sizeof(void *))
627         alignment = sizeof(void *);
628 
629     /* make sure alignment and offset didn't change */
630     saved = SAVED_PTR(memblock);
631     if (memblock != ALIGN_PTR(*saved, alignment, offset))
632     {
633         *MSVCRT__errno() = MSVCRT_EINVAL;
634         return NULL;
635     }
636 
637     old_padding = (char *)memblock - (char *)*saved;
638 
639     /* Get previous size of block */
640     old_size = _msize(*saved);
641     if (old_size == -1)
642     {
643         /* It seems this function was called with an invalid pointer. Bail out. */
644         return NULL;
645     }
646 
647     /* Adjust old_size to get amount of actual data in old block. */
648     if (old_size < old_padding)
649     {
650         /* Shouldn't happen. Something's weird, so bail out. */
651         return NULL;
652     }
653     old_size -= old_padding;
654 
655     temp = MSVCRT_realloc(*saved, size + alignment + sizeof(void *));
656 
657     if (!temp)
658         return NULL;
659 
660     /* adjust pointer for proper alignment and offset */
661     memblock = ALIGN_PTR(temp, alignment, offset);
662 
663     /* Save the real allocation address below returned address */
664     /* so it can be found later to free. */
665     saved = SAVED_PTR(memblock);
666 
667     new_padding = (char *)memblock - (char *)temp;
668 
669 /*
670    Memory layout of old block is as follows:
671    +-------+---------------------+-+--------------------------+-----------+
672    |  ...  | "old_padding" bytes | | ... "old_size" bytes ... |    ...    |
673    +-------+---------------------+-+--------------------------+-----------+
674            ^                     ^ ^
675            |                     | |
676         *saved               saved memblock
677 
678    Memory layout of new block is as follows:
679    +-------+-----------------------------+-+----------------------+-------+
680    |  ...  |    "new_padding" bytes      | | ... "size" bytes ... |  ...  |
681    +-------+-----------------------------+-+----------------------+-------+
682            ^                             ^ ^
683            |                             | |
684           temp                       saved memblock
685 
686    However, in the new block, actual data is still written as follows
687    (because it was copied by MSVCRT_realloc):
688    +-------+---------------------+--------------------------------+-------+
689    |  ...  | "old_padding" bytes |   ... "old_size" bytes ...     |  ...  |
690    +-------+---------------------+--------------------------------+-------+
691            ^                             ^ ^
692            |                             | |
693           temp                       saved memblock
694 
695    Therefore, min(old_size,size) bytes of actual data have to be moved
696    from the offset they were at in the old block (temp + old_padding),
697    to the offset they have to be in the new block (temp + new_padding == memblock).
698 */
699     if (new_padding != old_padding)
700         memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
701 
702     *saved = temp;
703 
704     return memblock;
705 }
706 
707 /*********************************************************************
708  *		_aligned_realloc (MSVCRT.@)
709  */
710 void * CDECL _aligned_realloc(void *memblock, MSVCRT_size_t size, MSVCRT_size_t alignment)
711 {
712     TRACE("(%p, %lu, %lu)\n", memblock, size, alignment);
713     return _aligned_offset_realloc(memblock, size, alignment, 0);
714 }
715 
716 /*********************************************************************
717  *		memmove_s (MSVCRT.@)
718  */
719 int CDECL MSVCRT_memmove_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
720 {
721     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
722 
723     if(!count)
724         return 0;
725 
726     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
727     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
728     if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE )) return MSVCRT_ERANGE;
729 
730     memmove(dest, src, count);
731     return 0;
732 }
733 
734 /*********************************************************************
735  *              wmemmove_s (MSVCR100.@)
736  */
737 int CDECL wmemmove_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
738         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
739 {
740     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
741 
742     if (!count)
743         return 0;
744 
745     /* Native does not seem to conform to 6.7.1.2.3 in
746      * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf
747      * in that it does not zero the output buffer on constraint violation.
748      */
749     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
750     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
751     if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) return MSVCRT_ERANGE;
752 
753     memmove(dest, src, sizeof(MSVCRT_wchar_t)*count);
754     return 0;
755 }
756 
757 /*********************************************************************
758  *		memcpy_s (MSVCRT.@)
759  */
760 int CDECL MSVCRT_memcpy_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
761 {
762     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
763 
764     if(!count)
765         return 0;
766 
767     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
768     if (!MSVCRT_CHECK_PMT(src != NULL))
769     {
770         memset(dest, 0, numberOfElements);
771         return MSVCRT_EINVAL;
772     }
773     if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE ))
774     {
775         memset(dest, 0, numberOfElements);
776         return MSVCRT_ERANGE;
777     }
778 
779     memcpy(dest, src, count);
780     return 0;
781 }
782 
783 /*********************************************************************
784  *              wmemcpy_s (MSVCR100.@)
785  */
786 int CDECL wmemcpy_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
787         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
788 {
789     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
790 
791     if (!count)
792         return 0;
793 
794     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
795 
796     if (!MSVCRT_CHECK_PMT(src != NULL)) {
797         memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
798         return MSVCRT_EINVAL;
799     }
800     if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) {
801         memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
802         return MSVCRT_ERANGE;
803     }
804 
805     memcpy(dest, src, sizeof(MSVCRT_wchar_t)*count);
806     return 0;
807 }
808 
809 /*********************************************************************
810  *		strncpy_s (MSVCRT.@)
811  */
812 int CDECL MSVCRT_strncpy_s(char *dest, MSVCRT_size_t numberOfElements,
813         const char *src, MSVCRT_size_t count)
814 {
815     MSVCRT_size_t i, end;
816 
817     TRACE("(%s %lu %s %lu)\n", dest, numberOfElements, src, count);
818 
819     if(!count) {
820         if(dest && numberOfElements)
821             *dest = 0;
822         return 0;
823     }
824 
825     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
826     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
827     if (!MSVCRT_CHECK_PMT(numberOfElements != 0)) return MSVCRT_EINVAL;
828 
829     if(count!=MSVCRT__TRUNCATE && count<numberOfElements)
830         end = count;
831     else
832         end = numberOfElements-1;
833 
834     for(i=0; i<end && src[i]; i++)
835         dest[i] = src[i];
836 
837     if(!src[i] || end==count || count==MSVCRT__TRUNCATE) {
838         dest[i] = '\0';
839         return 0;
840     }
841 
842     MSVCRT_INVALID_PMT("dest[numberOfElements] is too small", MSVCRT_EINVAL);
843     dest[0] = '\0';
844     return MSVCRT_EINVAL;
845 }
846 
847 BOOL msvcrt_init_heap(void)
848 {
849 #ifdef __REACTOS__
850     heap = GetProcessHeap();
851 #else
852     heap = HeapCreate(0, 0, 0);
853 #endif
854     return heap != NULL;
855 }
856 
857 void msvcrt_destroy_heap(void)
858 {
859     HeapDestroy(heap);
860     if(sb_heap)
861         HeapDestroy(sb_heap);
862 }
863