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