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