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