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