2 * msvcrt.dll heap functions
4 * Copyright 2000 Jon Griffiths
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.
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.
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
20 * Note: Win32 heap operations are MT safe. We only lock the new
21 * handler and non atomic heap operations
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
53 #define LOCK_HEAP _mlock( _HEAP_LOCK )
54 #define UNLOCK_HEAP _munlock( _HEAP_LOCK )
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))
63 #define SB_HEAP_ALIGN 16
65 static HANDLE heap
, sb_heap
;
67 typedef int (CDECL
*MSVCRT_new_handler_func
)(MSVCRT_size_t size
);
69 static MSVCRT_new_handler_func MSVCRT_new_handler
;
70 static int MSVCRT_new_mode
;
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;
77 static void* msvcrt_heap_alloc(DWORD flags
, MSVCRT_size_t size
)
79 if(size
< MSVCRT_sbh_threshold
)
81 void *memblock
, *temp
, **saved
;
83 temp
= HeapAlloc(sb_heap
, flags
, size
+sizeof(void*)+SB_HEAP_ALIGN
);
84 if(!temp
) return NULL
;
86 memblock
= ALIGN_PTR(temp
, SB_HEAP_ALIGN
, 0);
87 saved
= SAVED_PTR(memblock
);
92 return HeapAlloc(heap
, flags
, size
);
95 static void* msvcrt_heap_realloc(DWORD flags
, void *ptr
, MSVCRT_size_t size
)
97 if(sb_heap
&& ptr
&& !HeapValidate(heap
, 0, ptr
))
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
;
103 saved
= SAVED_PTR(ptr
);
104 old_padding
= (char*)ptr
- (char*)*saved
;
105 old_size
= HeapSize(sb_heap
, 0, *saved
);
108 old_size
-= old_padding
;
110 temp
= HeapReAlloc(sb_heap
, flags
, *saved
, size
+sizeof(void*)+SB_HEAP_ALIGN
);
111 if(!temp
) return NULL
;
113 memblock
= ALIGN_PTR(temp
, SB_HEAP_ALIGN
, 0);
114 saved
= SAVED_PTR(memblock
);
115 new_padding
= (char*)memblock
- (char*)temp
;
117 if(new_padding
!= old_padding
)
118 memmove(memblock
, (char*)temp
+old_padding
, old_size
>size
? size
: old_size
);
124 return HeapReAlloc(heap
, flags
, ptr
, size
);
127 static BOOL
msvcrt_heap_free(void *ptr
)
129 if(sb_heap
&& ptr
&& !HeapValidate(heap
, 0, ptr
))
131 void **saved
= SAVED_PTR(ptr
);
132 return HeapFree(sb_heap
, 0, *saved
);
135 return HeapFree(heap
, 0, ptr
);
138 static MSVCRT_size_t
msvcrt_heap_size(void *ptr
)
140 if(sb_heap
&& ptr
&& !HeapValidate(heap
, 0, ptr
))
142 void **saved
= SAVED_PTR(ptr
);
143 return HeapSize(sb_heap
, 0, *saved
);
146 return HeapSize(heap
, 0, ptr
);
149 /*********************************************************************
150 * ??2@YAPAXI@Z (MSVCRT.@)
152 void* CDECL
MSVCRT_operator_new(MSVCRT_size_t size
)
156 MSVCRT_new_handler_func handler
;
160 retval
= msvcrt_heap_alloc(0, size
);
163 TRACE("(%ld) returning %p\n", size
, retval
);
168 handler
= MSVCRT_new_handler
;
170 freed
= (*handler
)(size
);
176 TRACE("(%ld) out of memory\n", size
);
178 throw_bad_alloc("bad allocation");
184 /*********************************************************************
185 * ??2@YAPAXIHPBDH@Z (MSVCRT.@)
187 void* CDECL
MSVCRT_operator_new_dbg(MSVCRT_size_t size
, int type
, const char *file
, int line
)
189 return MSVCRT_operator_new( size
);
193 /*********************************************************************
194 * ??3@YAXPAX@Z (MSVCRT.@)
196 void CDECL
MSVCRT_operator_delete(void *mem
)
198 TRACE("(%p)\n", mem
);
199 msvcrt_heap_free(mem
);
203 /*********************************************************************
204 * ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@)
206 MSVCRT_new_handler_func CDECL
MSVCRT__query_new_handler(void)
208 return MSVCRT_new_handler
;
212 /*********************************************************************
213 * ?_query_new_mode@@YAHXZ (MSVCRT.@)
215 int CDECL
MSVCRT__query_new_mode(void)
217 return MSVCRT_new_mode
;
220 /*********************************************************************
221 * ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@)
223 MSVCRT_new_handler_func CDECL
MSVCRT__set_new_handler(MSVCRT_new_handler_func func
)
225 MSVCRT_new_handler_func old_handler
;
227 old_handler
= MSVCRT_new_handler
;
228 MSVCRT_new_handler
= func
;
233 /*********************************************************************
234 * ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
236 MSVCRT_new_handler_func CDECL
MSVCRT_set_new_handler(void *func
)
238 TRACE("(%p)\n",func
);
239 MSVCRT__set_new_handler(NULL
);
243 /*********************************************************************
244 * ?_set_new_mode@@YAHH@Z (MSVCRT.@)
246 int CDECL
MSVCRT__set_new_mode(int mode
)
250 old_mode
= MSVCRT_new_mode
;
251 MSVCRT_new_mode
= mode
;
256 /*********************************************************************
257 * _callnewh (MSVCRT.@)
259 int CDECL
_callnewh(MSVCRT_size_t size
)
262 MSVCRT_new_handler_func handler
= MSVCRT_new_handler
;
264 ret
= (*handler
)(size
) ? 1 : 0;
268 /*********************************************************************
271 void* CDECL
_expand(void* mem
, MSVCRT_size_t size
)
273 return msvcrt_heap_realloc(HEAP_REALLOC_IN_PLACE_ONLY
, mem
, size
);
276 /*********************************************************************
277 * _heapchk (MSVCRT.@)
279 int CDECL
_heapchk(void)
281 if (!HeapValidate(heap
, 0, NULL
) ||
282 (sb_heap
&& !HeapValidate(sb_heap
, 0, NULL
)))
284 msvcrt_set_errno(GetLastError());
285 return MSVCRT__HEAPBADNODE
;
287 return MSVCRT__HEAPOK
;
290 /*********************************************************************
291 * _heapmin (MSVCRT.@)
293 int CDECL
_heapmin(void)
295 if (!HeapCompact( heap
, 0 ) ||
296 (sb_heap
&& !HeapCompact( sb_heap
, 0 )))
298 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
299 msvcrt_set_errno(GetLastError());
305 /*********************************************************************
306 * _heapwalk (MSVCRT.@)
308 int CDECL
_heapwalk(struct MSVCRT__heapinfo
* next
)
310 PROCESS_HEAP_ENTRY phe
;
313 FIXME("small blocks heap not supported\n");
316 phe
.lpData
= next
->_pentry
;
317 phe
.cbData
= (DWORD
)next
->_size
;
318 phe
.wFlags
= next
->_useflag
== MSVCRT__USEDENTRY
? PROCESS_HEAP_ENTRY_BUSY
: 0;
320 if (phe
.lpData
&& phe
.wFlags
& PROCESS_HEAP_ENTRY_BUSY
&&
321 !HeapValidate( heap
, 0, phe
.lpData
))
324 msvcrt_set_errno(GetLastError());
325 return MSVCRT__HEAPBADNODE
;
330 if (!HeapWalk( heap
, &phe
))
333 if (GetLastError() == ERROR_NO_MORE_ITEMS
)
334 return MSVCRT__HEAPEND
;
335 msvcrt_set_errno(GetLastError());
337 return MSVCRT__HEAPBADBEGIN
;
338 return MSVCRT__HEAPBADNODE
;
340 } while (phe
.wFlags
& (PROCESS_HEAP_REGION
|PROCESS_HEAP_UNCOMMITTED_RANGE
));
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
;
349 /*********************************************************************
350 * _heapset (MSVCRT.@)
352 int CDECL
_heapset(unsigned int value
)
355 struct MSVCRT__heapinfo heap
;
357 memset( &heap
, 0, sizeof(heap
) );
359 while ((retval
= _heapwalk(&heap
)) == MSVCRT__HEAPOK
)
361 if (heap
._useflag
== MSVCRT__FREEENTRY
)
362 memset(heap
._pentry
, value
, heap
._size
);
365 return retval
== MSVCRT__HEAPEND
? MSVCRT__HEAPOK
: retval
;
368 /*********************************************************************
369 * _heapadd (MSVCRT.@)
371 int CDECL
_heapadd(void* mem
, MSVCRT_size_t size
)
373 TRACE("(%p,%ld) unsupported in Win32\n", mem
,size
);
374 *MSVCRT__errno() = MSVCRT_ENOSYS
;
378 /*********************************************************************
379 * _get_heap_handle (MSVCRT.@)
381 MSVCRT_intptr_t CDECL
_get_heap_handle(void)
383 return (MSVCRT_intptr_t
)heap
;
386 /*********************************************************************
389 MSVCRT_size_t CDECL
_msize(void* mem
)
391 MSVCRT_size_t size
= msvcrt_heap_size(mem
);
392 if (size
== ~(MSVCRT_size_t
)0)
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 */
400 /*********************************************************************
401 * _aligned_msize (MSVCR100.@)
403 size_t CDECL
_aligned_msize(void *p
, MSVCRT_size_t alignment
, MSVCRT_size_t offset
)
407 if(!MSVCRT_CHECK_PMT(p
)) return -1;
409 if(alignment
< sizeof(void*))
410 alignment
= sizeof(void*);
412 alloc_ptr
= SAVED_PTR(p
);
413 return _msize(*alloc_ptr
)-alignment
-sizeof(void*);
416 /*********************************************************************
419 void* CDECL
MSVCRT_calloc(MSVCRT_size_t count
, MSVCRT_size_t size
)
421 return msvcrt_heap_alloc(HEAP_ZERO_MEMORY
, count
*size
);
424 /*********************************************************************
427 void CDECL
MSVCRT_free(void* ptr
)
429 msvcrt_heap_free(ptr
);
432 /*********************************************************************
435 void* CDECL
MSVCRT_malloc(MSVCRT_size_t size
)
437 void *ret
= msvcrt_heap_alloc(0, size
);
439 *MSVCRT__errno() = MSVCRT_ENOMEM
;
443 /*********************************************************************
446 void* CDECL
MSVCRT_realloc(void* ptr
, MSVCRT_size_t size
)
448 if (!ptr
) return MSVCRT_malloc(size
);
449 if (size
) return msvcrt_heap_realloc(0, ptr
, size
);
454 /*********************************************************************
455 * _recalloc (MSVCR100.@)
457 void* CDECL
_recalloc(void *mem
, MSVCRT_size_t num
, MSVCRT_size_t size
)
459 MSVCRT_size_t old_size
;
463 return MSVCRT_calloc(num
, size
);
466 old_size
= _msize(mem
);
468 ret
= MSVCRT_realloc(mem
, size
);
470 *MSVCRT__errno() = MSVCRT_ENOMEM
;
475 memset((BYTE
*)ret
+old_size
, 0, size
-old_size
);
479 /*********************************************************************
480 * __p__amblksiz (MSVCRT.@)
482 unsigned int* CDECL
__p__amblksiz(void)
484 return &MSVCRT_amblksiz
;
487 /*********************************************************************
488 * _get_sbh_threshold (MSVCRT.@)
490 MSVCRT_size_t CDECL
_get_sbh_threshold(void)
492 return MSVCRT_sbh_threshold
;
495 /*********************************************************************
496 * _set_sbh_threshold (MSVCRT.@)
498 int CDECL
_set_sbh_threshold(MSVCRT_size_t threshold
)
508 sb_heap
= HeapCreate(0, 0, 0);
513 MSVCRT_sbh_threshold
= (threshold
+0xf) & ~0xf;
518 /*********************************************************************
519 * _aligned_free (MSVCRT.@)
521 void CDECL
_aligned_free(void *memblock
)
523 TRACE("(%p)\n", memblock
);
527 void **saved
= SAVED_PTR(memblock
);
532 /*********************************************************************
533 * _aligned_offset_malloc (MSVCRT.@)
535 void * CDECL
_aligned_offset_malloc(MSVCRT_size_t size
, MSVCRT_size_t alignment
, MSVCRT_size_t offset
)
537 void *memblock
, *temp
, **saved
;
538 TRACE("(%lu, %lu, %lu)\n", size
, alignment
, offset
);
540 /* alignment must be a power of 2 */
541 if ((alignment
& (alignment
- 1)) != 0)
543 *MSVCRT__errno() = MSVCRT_EINVAL
;
547 /* offset must be less than size */
550 *MSVCRT__errno() = MSVCRT_EINVAL
;
554 /* don't align to less than void pointer size */
555 if (alignment
< sizeof(void *))
556 alignment
= sizeof(void *);
558 /* allocate enough space for void pointer and alignment */
559 temp
= MSVCRT_malloc(size
+ alignment
+ sizeof(void *));
564 /* adjust pointer for proper alignment and offset */
565 memblock
= ALIGN_PTR(temp
, alignment
, offset
);
567 /* Save the real allocation address below returned address */
568 /* so it can be found later to free. */
569 saved
= SAVED_PTR(memblock
);
575 /*********************************************************************
576 * _aligned_malloc (MSVCRT.@)
578 void * CDECL
_aligned_malloc(MSVCRT_size_t size
, MSVCRT_size_t alignment
)
580 TRACE("(%lu, %lu)\n", size
, alignment
);
581 return _aligned_offset_malloc(size
, alignment
, 0);
584 /*********************************************************************
585 * _aligned_offset_realloc (MSVCRT.@)
587 void * CDECL
_aligned_offset_realloc(void *memblock
, MSVCRT_size_t size
,
588 MSVCRT_size_t alignment
, MSVCRT_size_t offset
)
590 void * temp
, **saved
;
591 MSVCRT_size_t old_padding
, new_padding
, old_size
;
592 TRACE("(%p, %lu, %lu, %lu)\n", memblock
, size
, alignment
, offset
);
595 return _aligned_offset_malloc(size
, alignment
, offset
);
597 /* alignment must be a power of 2 */
598 if ((alignment
& (alignment
- 1)) != 0)
600 *MSVCRT__errno() = MSVCRT_EINVAL
;
604 /* offset must be less than size */
607 *MSVCRT__errno() = MSVCRT_EINVAL
;
613 _aligned_free(memblock
);
617 /* don't align to less than void pointer size */
618 if (alignment
< sizeof(void *))
619 alignment
= sizeof(void *);
621 /* make sure alignment and offset didn't change */
622 saved
= SAVED_PTR(memblock
);
623 if (memblock
!= ALIGN_PTR(*saved
, alignment
, offset
))
625 *MSVCRT__errno() = MSVCRT_EINVAL
;
629 old_padding
= (char *)memblock
- (char *)*saved
;
631 /* Get previous size of block */
632 old_size
= _msize(*saved
);
635 /* It seems this function was called with an invalid pointer. Bail out. */
639 /* Adjust old_size to get amount of actual data in old block. */
640 if (old_size
< old_padding
)
642 /* Shouldn't happen. Something's weird, so bail out. */
645 old_size
-= old_padding
;
647 temp
= MSVCRT_realloc(*saved
, size
+ alignment
+ sizeof(void *));
652 /* adjust pointer for proper alignment and offset */
653 memblock
= ALIGN_PTR(temp
, alignment
, offset
);
655 /* Save the real allocation address below returned address */
656 /* so it can be found later to free. */
657 saved
= SAVED_PTR(memblock
);
659 new_padding
= (char *)memblock
- (char *)temp
;
662 Memory layout of old block is as follows:
663 +-------+---------------------+-+--------------------------+-----------+
664 | ... | "old_padding" bytes | | ... "old_size" bytes ... | ... |
665 +-------+---------------------+-+--------------------------+-----------+
668 *saved saved memblock
670 Memory layout of new block is as follows:
671 +-------+-----------------------------+-+----------------------+-------+
672 | ... | "new_padding" bytes | | ... "size" bytes ... | ... |
673 +-------+-----------------------------+-+----------------------+-------+
678 However, in the new block, actual data is still written as follows
679 (because it was copied by MSVCRT_realloc):
680 +-------+---------------------+--------------------------------+-------+
681 | ... | "old_padding" bytes | ... "old_size" bytes ... | ... |
682 +-------+---------------------+--------------------------------+-------+
687 Therefore, min(old_size,size) bytes of actual data have to be moved
688 from the offset they were at in the old block (temp + old_padding),
689 to the offset they have to be in the new block (temp + new_padding == memblock).
691 if (new_padding
!= old_padding
)
692 memmove((char *)memblock
, (char *)temp
+ old_padding
, (old_size
< size
) ? old_size
: size
);
699 /*********************************************************************
700 * _aligned_realloc (MSVCRT.@)
702 void * CDECL
_aligned_realloc(void *memblock
, MSVCRT_size_t size
, MSVCRT_size_t alignment
)
704 TRACE("(%p, %lu, %lu)\n", memblock
, size
, alignment
);
705 return _aligned_offset_realloc(memblock
, size
, alignment
, 0);
708 /*********************************************************************
709 * memmove_s (MSVCRT.@)
711 int CDECL
MSVCRT_memmove_s(void *dest
, MSVCRT_size_t numberOfElements
, const void *src
, MSVCRT_size_t count
)
713 TRACE("(%p %lu %p %lu)\n", dest
, numberOfElements
, src
, count
);
720 memset(dest
, 0, numberOfElements
);
726 if(count
> numberOfElements
) {
727 memset(dest
, 0, numberOfElements
);
733 memmove(dest
, src
, count
);
737 /*********************************************************************
738 * wmemmove_s (MSVCR100.@)
740 int CDECL
wmemmove_s(MSVCRT_wchar_t
*dest
, MSVCRT_size_t numberOfElements
,
741 const MSVCRT_wchar_t
*src
, MSVCRT_size_t count
)
743 TRACE("(%p %lu %p %lu)\n", dest
, numberOfElements
, src
, count
);
748 /* Native does not seem to conform to 6.7.1.2.3 in
749 * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf
750 * in that it does not zero the output buffer on constraint violation.
752 if (!MSVCRT_CHECK_PMT(dest
!= NULL
)) return MSVCRT_EINVAL
;
753 if (!MSVCRT_CHECK_PMT(src
!= NULL
)) return MSVCRT_EINVAL
;
754 if (!MSVCRT_CHECK_PMT_ERR(count
<= numberOfElements
, MSVCRT_ERANGE
)) return MSVCRT_ERANGE
;
756 memmove(dest
, src
, sizeof(MSVCRT_wchar_t
)*count
);
760 /*********************************************************************
761 * memcpy_s (MSVCRT.@)
763 int CDECL
MSVCRT_memcpy_s(void *dest
, MSVCRT_size_t numberOfElements
, const void *src
, MSVCRT_size_t count
)
765 TRACE("(%p %lu %p %lu)\n", dest
, numberOfElements
, src
, count
);
770 if (!MSVCRT_CHECK_PMT(dest
!= NULL
)) return MSVCRT_EINVAL
;
771 if (!MSVCRT_CHECK_PMT(src
!= NULL
))
773 memset(dest
, 0, numberOfElements
);
774 return MSVCRT_EINVAL
;
776 if (!MSVCRT_CHECK_PMT_ERR( count
<= numberOfElements
, MSVCRT_ERANGE
))
778 memset(dest
, 0, numberOfElements
);
779 return MSVCRT_ERANGE
;
782 memcpy(dest
, src
, count
);
786 /*********************************************************************
787 * wmemcpy_s (MSVCR100.@)
789 int CDECL
wmemcpy_s(MSVCRT_wchar_t
*dest
, MSVCRT_size_t numberOfElements
,
790 const MSVCRT_wchar_t
*src
, MSVCRT_size_t count
)
792 TRACE("(%p %lu %p %lu)\n", dest
, numberOfElements
, src
, count
);
797 if (!MSVCRT_CHECK_PMT(dest
!= NULL
)) return MSVCRT_EINVAL
;
799 if (!MSVCRT_CHECK_PMT(src
!= NULL
)) {
800 memset(dest
, 0, numberOfElements
*sizeof(MSVCRT_wchar_t
));
801 return MSVCRT_EINVAL
;
803 if (!MSVCRT_CHECK_PMT_ERR(count
<= numberOfElements
, MSVCRT_ERANGE
)) {
804 memset(dest
, 0, numberOfElements
*sizeof(MSVCRT_wchar_t
));
805 return MSVCRT_ERANGE
;
808 memcpy(dest
, src
, sizeof(MSVCRT_wchar_t
)*count
);
812 /*********************************************************************
813 * strncpy_s (MSVCRT.@)
815 int CDECL
MSVCRT_strncpy_s(char *dest
, MSVCRT_size_t numberOfElements
,
816 const char *src
, MSVCRT_size_t count
)
818 MSVCRT_size_t i
, end
;
820 TRACE("(%s %lu %s %lu)\n", dest
, numberOfElements
, src
, count
);
823 if(dest
&& numberOfElements
)
828 if (!MSVCRT_CHECK_PMT(dest
!= NULL
)) return MSVCRT_EINVAL
;
829 if (!MSVCRT_CHECK_PMT(src
!= NULL
)) return MSVCRT_EINVAL
;
830 if (!MSVCRT_CHECK_PMT(numberOfElements
!= 0)) return MSVCRT_EINVAL
;
832 if(count
!=MSVCRT__TRUNCATE
&& count
<numberOfElements
)
835 end
= numberOfElements
-1;
837 for(i
=0; i
<end
&& src
[i
]; i
++)
840 if(!src
[i
] || end
==count
|| count
==MSVCRT__TRUNCATE
) {
845 MSVCRT_INVALID_PMT("dest[numberOfElements] is too small", MSVCRT_EINVAL
);
847 return MSVCRT_EINVAL
;
850 BOOL
msvcrt_init_heap(void)
853 heap
= GetProcessHeap();
855 heap
= HeapCreate(0, 0, 0);
860 void msvcrt_destroy_heap(void)
864 HeapDestroy(sb_heap
);