xref: /reactos/sdk/lib/crt/wine/heap.c (revision 8fdc1b0d)
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_exception(EXCEPTION_BAD_ALLOC, 0, "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  *		_calloc_base (UCRTBASE.@)
434  */
435 void* CDECL _calloc_base(MSVCRT_size_t count, MSVCRT_size_t size)
436 {
437   return MSVCRT_calloc(count, size);
438 }
439 
440 /*********************************************************************
441  *		free (MSVCRT.@)
442  */
443 void CDECL MSVCRT_free(void* ptr)
444 {
445   msvcrt_heap_free(ptr);
446 }
447 
448 /*********************************************************************
449  *		_free_base (UCRTBASE.@)
450  */
451 void CDECL _free_base(void* ptr)
452 {
453   msvcrt_heap_free(ptr);
454 }
455 
456 /*********************************************************************
457  *                  malloc (MSVCRT.@)
458  */
459 void* CDECL MSVCRT_malloc(MSVCRT_size_t size)
460 {
461   void *ret = msvcrt_heap_alloc(0, size);
462   if (!ret)
463       *MSVCRT__errno() = MSVCRT_ENOMEM;
464   return ret;
465 }
466 
467 /*********************************************************************
468  *                  _malloc_base (UCRTBASE.@)
469  */
470 void* CDECL _malloc_base(MSVCRT_size_t size)
471 {
472   return MSVCRT_malloc(size);
473 }
474 
475 /*********************************************************************
476  *		realloc (MSVCRT.@)
477  */
478 void* CDECL MSVCRT_realloc(void* ptr, MSVCRT_size_t size)
479 {
480   if (!ptr) return MSVCRT_malloc(size);
481   if (size) return msvcrt_heap_realloc(0, ptr, size);
482   MSVCRT_free(ptr);
483   return NULL;
484 }
485 
486 /*********************************************************************
487  *		_realloc_base (UCRTBASE.@)
488  */
489 void* CDECL _realloc_base(void* ptr, MSVCRT_size_t size)
490 {
491   return MSVCRT_realloc(ptr, size);
492 }
493 
494 /*********************************************************************
495  * _recalloc (MSVCR100.@)
496  */
497 void* CDECL _recalloc(void *mem, MSVCRT_size_t num, MSVCRT_size_t size)
498 {
499     MSVCRT_size_t old_size;
500     void *ret;
501 
502     if(!mem)
503         return MSVCRT_calloc(num, size);
504 
505     size = num*size;
506     old_size = _msize(mem);
507 
508     ret = MSVCRT_realloc(mem, size);
509     if(!ret) {
510         *MSVCRT__errno() = MSVCRT_ENOMEM;
511         return NULL;
512     }
513 
514     if(size>old_size)
515         memset((BYTE*)ret+old_size, 0, size-old_size);
516     return ret;
517 }
518 
519 /*********************************************************************
520  *		__p__amblksiz (MSVCRT.@)
521  */
522 unsigned int* CDECL __p__amblksiz(void)
523 {
524   return &MSVCRT_amblksiz;
525 }
526 
527 /*********************************************************************
528  *		_get_sbh_threshold (MSVCRT.@)
529  */
530 MSVCRT_size_t CDECL _get_sbh_threshold(void)
531 {
532   return MSVCRT_sbh_threshold;
533 }
534 
535 /*********************************************************************
536  *		_set_sbh_threshold (MSVCRT.@)
537  */
538 int CDECL _set_sbh_threshold(MSVCRT_size_t threshold)
539 {
540 #ifdef _WIN64
541   return 0;
542 #else
543   if(threshold > 1016)
544      return 0;
545 
546   if(!sb_heap)
547   {
548       sb_heap = HeapCreate(0, 0, 0);
549       if(!sb_heap)
550           return 0;
551   }
552 
553   MSVCRT_sbh_threshold = (threshold+0xf) & ~0xf;
554   return 1;
555 #endif
556 }
557 
558 /*********************************************************************
559  *		_aligned_free (MSVCRT.@)
560  */
561 void CDECL _aligned_free(void *memblock)
562 {
563     TRACE("(%p)\n", memblock);
564 
565     if (memblock)
566     {
567         void **saved = SAVED_PTR(memblock);
568         MSVCRT_free(*saved);
569     }
570 }
571 
572 /*********************************************************************
573  *		_aligned_offset_malloc (MSVCRT.@)
574  */
575 void * CDECL _aligned_offset_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment, MSVCRT_size_t offset)
576 {
577     void *memblock, *temp, **saved;
578     TRACE("(%lu, %lu, %lu)\n", size, alignment, offset);
579 
580     /* alignment must be a power of 2 */
581     if ((alignment & (alignment - 1)) != 0)
582     {
583         *MSVCRT__errno() = MSVCRT_EINVAL;
584         return NULL;
585     }
586 
587     /* offset must be less than size */
588     if (offset && offset >= size)
589     {
590         *MSVCRT__errno() = MSVCRT_EINVAL;
591         return NULL;
592     }
593 
594     /* don't align to less than void pointer size */
595     if (alignment < sizeof(void *))
596         alignment = sizeof(void *);
597 
598     /* allocate enough space for void pointer and alignment */
599     temp = MSVCRT_malloc(size + alignment + sizeof(void *));
600 
601     if (!temp)
602         return NULL;
603 
604     /* adjust pointer for proper alignment and offset */
605     memblock = ALIGN_PTR(temp, alignment, offset);
606 
607     /* Save the real allocation address below returned address */
608     /* so it can be found later to free. */
609     saved = SAVED_PTR(memblock);
610     *saved = temp;
611 
612     return memblock;
613 }
614 
615 /*********************************************************************
616  *		_aligned_malloc (MSVCRT.@)
617  */
618 void * CDECL _aligned_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment)
619 {
620     TRACE("(%lu, %lu)\n", size, alignment);
621     return _aligned_offset_malloc(size, alignment, 0);
622 }
623 
624 /*********************************************************************
625  *		_aligned_offset_realloc (MSVCRT.@)
626  */
627 void * CDECL _aligned_offset_realloc(void *memblock, MSVCRT_size_t size,
628                                      MSVCRT_size_t alignment, MSVCRT_size_t offset)
629 {
630     void * temp, **saved;
631     MSVCRT_size_t old_padding, new_padding, old_size;
632     TRACE("(%p, %lu, %lu, %lu)\n", memblock, size, alignment, offset);
633 
634     if (!memblock)
635         return _aligned_offset_malloc(size, alignment, offset);
636 
637     /* alignment must be a power of 2 */
638     if ((alignment & (alignment - 1)) != 0)
639     {
640         *MSVCRT__errno() = MSVCRT_EINVAL;
641         return NULL;
642     }
643 
644     /* offset must be less than size */
645     if (offset >= size)
646     {
647         *MSVCRT__errno() = MSVCRT_EINVAL;
648         return NULL;
649     }
650 
651     if (size == 0)
652     {
653         _aligned_free(memblock);
654         return NULL;
655     }
656 
657     /* don't align to less than void pointer size */
658     if (alignment < sizeof(void *))
659         alignment = sizeof(void *);
660 
661     /* make sure alignment and offset didn't change */
662     saved = SAVED_PTR(memblock);
663     if (memblock != ALIGN_PTR(*saved, alignment, offset))
664     {
665         *MSVCRT__errno() = MSVCRT_EINVAL;
666         return NULL;
667     }
668 
669     old_padding = (char *)memblock - (char *)*saved;
670 
671     /* Get previous size of block */
672     old_size = _msize(*saved);
673     if (old_size == -1)
674     {
675         /* It seems this function was called with an invalid pointer. Bail out. */
676         return NULL;
677     }
678 
679     /* Adjust old_size to get amount of actual data in old block. */
680     if (old_size < old_padding)
681     {
682         /* Shouldn't happen. Something's weird, so bail out. */
683         return NULL;
684     }
685     old_size -= old_padding;
686 
687     temp = MSVCRT_realloc(*saved, size + alignment + sizeof(void *));
688 
689     if (!temp)
690         return NULL;
691 
692     /* adjust pointer for proper alignment and offset */
693     memblock = ALIGN_PTR(temp, alignment, offset);
694 
695     /* Save the real allocation address below returned address */
696     /* so it can be found later to free. */
697     saved = SAVED_PTR(memblock);
698 
699     new_padding = (char *)memblock - (char *)temp;
700 
701 /*
702    Memory layout of old block is as follows:
703    +-------+---------------------+-+--------------------------+-----------+
704    |  ...  | "old_padding" bytes | | ... "old_size" bytes ... |    ...    |
705    +-------+---------------------+-+--------------------------+-----------+
706            ^                     ^ ^
707            |                     | |
708         *saved               saved memblock
709 
710    Memory layout of new block is as follows:
711    +-------+-----------------------------+-+----------------------+-------+
712    |  ...  |    "new_padding" bytes      | | ... "size" bytes ... |  ...  |
713    +-------+-----------------------------+-+----------------------+-------+
714            ^                             ^ ^
715            |                             | |
716           temp                       saved memblock
717 
718    However, in the new block, actual data is still written as follows
719    (because it was copied by MSVCRT_realloc):
720    +-------+---------------------+--------------------------------+-------+
721    |  ...  | "old_padding" bytes |   ... "old_size" bytes ...     |  ...  |
722    +-------+---------------------+--------------------------------+-------+
723            ^                             ^ ^
724            |                             | |
725           temp                       saved memblock
726 
727    Therefore, min(old_size,size) bytes of actual data have to be moved
728    from the offset they were at in the old block (temp + old_padding),
729    to the offset they have to be in the new block (temp + new_padding == memblock).
730 */
731     if (new_padding != old_padding)
732         memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
733 
734     *saved = temp;
735 
736     return memblock;
737 }
738 
739 /*********************************************************************
740  *		_aligned_realloc (MSVCRT.@)
741  */
742 void * CDECL _aligned_realloc(void *memblock, MSVCRT_size_t size, MSVCRT_size_t alignment)
743 {
744     TRACE("(%p, %lu, %lu)\n", memblock, size, alignment);
745     return _aligned_offset_realloc(memblock, size, alignment, 0);
746 }
747 
748 /*********************************************************************
749  *		memmove_s (MSVCRT.@)
750  */
751 int CDECL MSVCRT_memmove_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
752 {
753     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
754 
755     if(!count)
756         return 0;
757 
758     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
759     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
760     if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE )) return MSVCRT_ERANGE;
761 
762     memmove(dest, src, count);
763     return 0;
764 }
765 
766 /*********************************************************************
767  *              wmemmove_s (MSVCR100.@)
768  */
769 int CDECL wmemmove_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
770         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
771 {
772     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
773 
774     if (!count)
775         return 0;
776 
777     /* Native does not seem to conform to 6.7.1.2.3 in
778      * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf
779      * in that it does not zero the output buffer on constraint violation.
780      */
781     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
782     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
783     if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) return MSVCRT_ERANGE;
784 
785     memmove(dest, src, sizeof(MSVCRT_wchar_t)*count);
786     return 0;
787 }
788 
789 /*********************************************************************
790  *		memcpy_s (MSVCRT.@)
791  */
792 int CDECL MSVCRT_memcpy_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
793 {
794     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
795 
796     if(!count)
797         return 0;
798 
799     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
800     if (!MSVCRT_CHECK_PMT(src != NULL))
801     {
802         memset(dest, 0, numberOfElements);
803         return MSVCRT_EINVAL;
804     }
805     if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE ))
806     {
807         memset(dest, 0, numberOfElements);
808         return MSVCRT_ERANGE;
809     }
810 
811     memcpy(dest, src, count);
812     return 0;
813 }
814 
815 /*********************************************************************
816  *              wmemcpy_s (MSVCR100.@)
817  */
818 int CDECL wmemcpy_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
819         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
820 {
821     TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
822 
823     if (!count)
824         return 0;
825 
826     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
827 
828     if (!MSVCRT_CHECK_PMT(src != NULL)) {
829         memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
830         return MSVCRT_EINVAL;
831     }
832     if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) {
833         memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
834         return MSVCRT_ERANGE;
835     }
836 
837     memcpy(dest, src, sizeof(MSVCRT_wchar_t)*count);
838     return 0;
839 }
840 
841 /*********************************************************************
842  *		strncpy_s (MSVCRT.@)
843  */
844 int CDECL MSVCRT_strncpy_s(char *dest, MSVCRT_size_t numberOfElements,
845         const char *src, MSVCRT_size_t count)
846 {
847     MSVCRT_size_t i, end;
848 
849     TRACE("(%s %lu %s %lu)\n", dest, numberOfElements, src, count);
850 
851     if(!count) {
852         if(dest && numberOfElements)
853             *dest = 0;
854         return 0;
855     }
856 
857     if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
858     if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
859     if (!MSVCRT_CHECK_PMT(numberOfElements != 0)) return MSVCRT_EINVAL;
860 
861     if(count!=MSVCRT__TRUNCATE && count<numberOfElements)
862         end = count;
863     else
864         end = numberOfElements-1;
865 
866     for(i=0; i<end && src[i]; i++)
867         dest[i] = src[i];
868 
869     if(!src[i] || end==count || count==MSVCRT__TRUNCATE) {
870         dest[i] = '\0';
871         return 0;
872     }
873 
874     MSVCRT_INVALID_PMT("dest[numberOfElements] is too small", MSVCRT_EINVAL);
875     dest[0] = '\0';
876     return MSVCRT_EINVAL;
877 }
878 
879 BOOL msvcrt_init_heap(void)
880 {
881 #ifdef __REACTOS__
882     heap = GetProcessHeap();
883 #else
884     heap = HeapCreate(0, 0, 0);
885 #endif
886     return heap != NULL;
887 }
888 
889 void msvcrt_destroy_heap(void)
890 {
891     HeapDestroy(heap);
892     if(sb_heap)
893         HeapDestroy(sb_heap);
894 }
895