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