heap.c 22.1 KB
Newer Older
1 2 3 4 5
/*
 * msvcrt.dll heap functions
 *
 * Copyright 2000 Jon Griffiths
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 21 22 23 24
 * Note: Win32 heap operations are MT safe. We only lock the new
 *       handler and non atomic heap operations
 */

#include "msvcrt.h"
25
#include "mtdll.h"
26 27 28
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
29 30

/* MT */
31 32 33
#define LOCK_HEAP   _mlock( _HEAP_LOCK )
#define UNLOCK_HEAP _munlock( _HEAP_LOCK )

34 35 36 37 38 39 40
/* _aligned */
#define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
                               ~(sizeof(void *) - 1)))
#define ALIGN_PTR(ptr, alignment, offset) ((void *) \
    ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \
      ~(alignment - 1)) - offset))

41 42 43
#define SB_HEAP_ALIGN 16

static HANDLE heap, sb_heap;
44

45
typedef int (CDECL *MSVCRT_new_handler_func)(MSVCRT_size_t size);
46 47 48 49

static MSVCRT_new_handler_func MSVCRT_new_handler;
static int MSVCRT_new_mode;

50 51
/* FIXME - According to documentation it should be 8*1024, at runtime it returns 16 */ 
static unsigned int MSVCRT_amblksiz = 16;
52
/* FIXME - According to documentation it should be 480 bytes, at runtime default is 0 */
53
static MSVCRT_size_t MSVCRT_sbh_threshold = 0;
54

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
static void* msvcrt_heap_alloc(DWORD flags, MSVCRT_size_t size)
{
    if(size < MSVCRT_sbh_threshold)
    {
        void *memblock, *temp, **saved;

        temp = HeapAlloc(sb_heap, flags, size+sizeof(void*)+SB_HEAP_ALIGN);
        if(!temp) return NULL;

        memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
        saved = SAVED_PTR(memblock);
        *saved = temp;
        return memblock;
    }

    return HeapAlloc(heap, flags, size);
}

static void* msvcrt_heap_realloc(DWORD flags, void *ptr, MSVCRT_size_t size)
{
    if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
    {
        /* TODO: move data to normal heap if it exceeds sbh_threshold limit */
        void *memblock, *temp, **saved;
        MSVCRT_size_t old_padding, new_padding, old_size;

        saved = SAVED_PTR(ptr);
        old_padding = (char*)ptr - (char*)*saved;
        old_size = HeapSize(sb_heap, 0, *saved);
        if(old_size == -1)
            return NULL;
        old_size -= old_padding;

        temp = HeapReAlloc(sb_heap, flags, *saved, size+sizeof(void*)+SB_HEAP_ALIGN);
        if(!temp) return NULL;

        memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
        saved = SAVED_PTR(memblock);
        new_padding = (char*)memblock - (char*)temp;

        if(new_padding != old_padding)
            memmove(memblock, (char*)temp+old_padding, old_size>size ? size : old_size);

        *saved = temp;
        return memblock;
    }

    return HeapReAlloc(heap, flags, ptr, size);
}

static BOOL msvcrt_heap_free(void *ptr)
{
    if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
    {
        void **saved = SAVED_PTR(ptr);
        return HeapFree(sb_heap, 0, *saved);
    }

    return HeapFree(heap, 0, ptr);
}

static MSVCRT_size_t msvcrt_heap_size(void *ptr)
{
    if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
    {
        void **saved = SAVED_PTR(ptr);
        return HeapSize(sb_heap, 0, *saved);
    }

    return HeapSize(heap, 0, ptr);
}

127
/*********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
128
 *		??2@YAPAXI@Z (MSVCRT.@)
129
 */
130
void* CDECL MSVCRT_operator_new(MSVCRT_size_t size)
131
{
132 133 134 135 136
  void *retval;
  int freed;

  do
  {
137
    retval = msvcrt_heap_alloc(0, size);
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    if(retval)
    {
      TRACE("(%ld) returning %p\n", size, retval);
      return retval;
    }

    LOCK_HEAP;
    if(MSVCRT_new_handler)
      freed = (*MSVCRT_new_handler)(size);
    else
      freed = 0;
    UNLOCK_HEAP;
  } while(freed);

  TRACE("(%ld) out of memory\n", size);
153 154 155
#if _MSVCR_VER >= 80
  throw_bad_alloc("bad allocation");
#endif
156
  return NULL;
157 158
}

159 160 161 162 163 164 165 166 167 168

/*********************************************************************
 *		??2@YAPAXIHPBDH@Z (MSVCRT.@)
 */
void* CDECL MSVCRT_operator_new_dbg(MSVCRT_size_t size, int type, const char *file, int line)
{
    return MSVCRT_operator_new( size );
}


169
/*********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
170
 *		??3@YAXPAX@Z (MSVCRT.@)
171
 */
172
void CDECL MSVCRT_operator_delete(void *mem)
173 174
{
  TRACE("(%p)\n", mem);
175
  msvcrt_heap_free(mem);
176 177 178 179 180 181
}


/*********************************************************************
 *		?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@)
 */
182
MSVCRT_new_handler_func CDECL MSVCRT__query_new_handler(void)
183 184 185 186 187 188 189 190
{
  return MSVCRT_new_handler;
}


/*********************************************************************
 *		?_query_new_mode@@YAHXZ (MSVCRT.@)
 */
191
int CDECL MSVCRT__query_new_mode(void)
192 193 194 195 196 197 198
{
  return MSVCRT_new_mode;
}

/*********************************************************************
 *		?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@)
 */
199
MSVCRT_new_handler_func CDECL MSVCRT__set_new_handler(MSVCRT_new_handler_func func)
200 201 202 203 204 205 206 207 208
{
  MSVCRT_new_handler_func old_handler;
  LOCK_HEAP;
  old_handler = MSVCRT_new_handler;
  MSVCRT_new_handler = func;
  UNLOCK_HEAP;
  return old_handler;
}

209 210 211
/*********************************************************************
 *		?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
 */
212
MSVCRT_new_handler_func CDECL MSVCRT_set_new_handler(void *func)
213 214 215 216 217 218
{
  TRACE("(%p)\n",func);
  MSVCRT__set_new_handler(NULL);
  return NULL;
}

219 220 221
/*********************************************************************
 *		?_set_new_mode@@YAHH@Z (MSVCRT.@)
 */
222
int CDECL MSVCRT__set_new_mode(int mode)
223 224 225 226 227 228 229 230 231
{
  int old_mode;
  LOCK_HEAP;
  old_mode = MSVCRT_new_mode;
  MSVCRT_new_mode = mode;
  UNLOCK_HEAP;
  return old_mode;
}

232 233 234
/*********************************************************************
 *		_callnewh (MSVCRT.@)
 */
235
int CDECL _callnewh(MSVCRT_size_t size)
236 237 238 239 240 241
{
  if(MSVCRT_new_handler)
    (*MSVCRT_new_handler)(size);
  return 0;
}

242 243 244
/*********************************************************************
 *		_expand (MSVCRT.@)
 */
245
void* CDECL _expand(void* mem, MSVCRT_size_t size)
246
{
247
  return msvcrt_heap_realloc(HEAP_REALLOC_IN_PLACE_ONLY, mem, size);
248 249 250 251 252
}

/*********************************************************************
 *		_heapchk (MSVCRT.@)
 */
253
int CDECL _heapchk(void)
254
{
255 256
  if (!HeapValidate(heap, 0, NULL) ||
          (sb_heap && !HeapValidate(sb_heap, 0, NULL)))
257
  {
258 259
    msvcrt_set_errno(GetLastError());
    return MSVCRT__HEAPBADNODE;
260
  }
261
  return MSVCRT__HEAPOK;
262 263 264 265 266
}

/*********************************************************************
 *		_heapmin (MSVCRT.@)
 */
267
int CDECL _heapmin(void)
268
{
269 270
  if (!HeapCompact( heap, 0 ) ||
          (sb_heap && !HeapCompact( sb_heap, 0 )))
271 272
  {
    if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
273
      msvcrt_set_errno(GetLastError());
274 275 276 277 278 279 280 281
    return -1;
  }
  return 0;
}

/*********************************************************************
 *		_heapwalk (MSVCRT.@)
 */
282
int CDECL _heapwalk(struct MSVCRT__heapinfo* next)
283 284 285
{
  PROCESS_HEAP_ENTRY phe;

286 287 288
  if (sb_heap)
      FIXME("small blocks heap not supported\n");

289 290 291
  LOCK_HEAP;
  phe.lpData = next->_pentry;
  phe.cbData = next->_size;
292
  phe.wFlags = next->_useflag == MSVCRT__USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0;
293 294

  if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY &&
295
      !HeapValidate( heap, 0, phe.lpData ))
296 297
  {
    UNLOCK_HEAP;
298 299
    msvcrt_set_errno(GetLastError());
    return MSVCRT__HEAPBADNODE;
300 301 302 303
  }

  do
  {
304
    if (!HeapWalk( heap, &phe ))
305 306 307
    {
      UNLOCK_HEAP;
      if (GetLastError() == ERROR_NO_MORE_ITEMS)
308 309
         return MSVCRT__HEAPEND;
      msvcrt_set_errno(GetLastError());
310
      if (!phe.lpData)
311 312
        return MSVCRT__HEAPBADBEGIN;
      return MSVCRT__HEAPBADNODE;
313 314 315 316 317 318
    }
  } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE));

  UNLOCK_HEAP;
  next->_pentry = phe.lpData;
  next->_size = phe.cbData;
319 320
  next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? MSVCRT__USEDENTRY : MSVCRT__FREEENTRY;
  return MSVCRT__HEAPOK;
321 322 323 324 325
}

/*********************************************************************
 *		_heapset (MSVCRT.@)
 */
326
int CDECL _heapset(unsigned int value)
327 328
{
  int retval;
329
  struct MSVCRT__heapinfo heap;
330

331
  memset( &heap, 0, sizeof(heap) );
332
  LOCK_HEAP;
333
  while ((retval = _heapwalk(&heap)) == MSVCRT__HEAPOK)
334
  {
335
    if (heap._useflag == MSVCRT__FREEENTRY)
336 337 338
      memset(heap._pentry, value, heap._size);
  }
  UNLOCK_HEAP;
339
  return retval == MSVCRT__HEAPEND? MSVCRT__HEAPOK : retval;
340 341
}

342 343 344
/*********************************************************************
 *		_heapadd (MSVCRT.@)
 */
345
int CDECL _heapadd(void* mem, MSVCRT_size_t size)
346
{
347
  TRACE("(%p,%ld) unsupported in Win32\n", mem,size);
348
  *MSVCRT__errno() = MSVCRT_ENOSYS;
349 350 351
  return -1;
}

352
/*********************************************************************
353
 *		_get_heap_handle (MSVCRT.@)
354 355 356
 */
MSVCRT_intptr_t CDECL _get_heap_handle(void)
{
357
    return (MSVCRT_intptr_t)heap;
358 359
}

360 361 362
/*********************************************************************
 *		_msize (MSVCRT.@)
 */
363
MSVCRT_size_t CDECL _msize(void* mem)
364
{
365
  MSVCRT_size_t size = msvcrt_heap_size(mem);
366
  if (size == ~(MSVCRT_size_t)0)
367 368 369 370 371 372 373
  {
    WARN(":Probably called with non wine-allocated memory, ret = -1\n");
    /* At least the Win32 crtdll/msvcrt also return -1 in this case */
  }
  return size;
}

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
/*********************************************************************
 * _aligned_msize (MSVCR100.@)
 */
size_t CDECL _aligned_msize(void *p, MSVCRT_size_t alignment, MSVCRT_size_t offset)
{
    void **alloc_ptr;

    if(!MSVCRT_CHECK_PMT(p)) return -1;

    if(alignment < sizeof(void*))
        alignment = sizeof(void*);

    alloc_ptr = SAVED_PTR(p);
    return _msize(*alloc_ptr)-alignment-sizeof(void*);
}

390 391 392
/*********************************************************************
 *		calloc (MSVCRT.@)
 */
393
void* CDECL MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count)
394
{
395
  return msvcrt_heap_alloc(HEAP_ZERO_MEMORY, size*count);
396 397 398 399 400
}

/*********************************************************************
 *		free (MSVCRT.@)
 */
401
void CDECL MSVCRT_free(void* ptr)
402
{
403
  msvcrt_heap_free(ptr);
404 405 406 407 408
}

/*********************************************************************
 *                  malloc (MSVCRT.@)
 */
409
void* CDECL MSVCRT_malloc(MSVCRT_size_t size)
410
{
411
  void *ret = msvcrt_heap_alloc(0, size);
412
  if (!ret)
413
      *MSVCRT__errno() = MSVCRT_ENOMEM;
414 415 416 417 418 419
  return ret;
}

/*********************************************************************
 *		realloc (MSVCRT.@)
 */
420
void* CDECL MSVCRT_realloc(void* ptr, MSVCRT_size_t size)
421
{
422
  if (!ptr) return MSVCRT_malloc(size);
423
  if (size) return msvcrt_heap_realloc(0, ptr, size);
424 425
  MSVCRT_free(ptr);
  return NULL;
426
}
427

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
/*********************************************************************
 * _recalloc (MSVCR100.@)
 */
void* CDECL _recalloc(void *mem, MSVCRT_size_t num, MSVCRT_size_t size)
{
    MSVCRT_size_t old_size;
    void *ret;

    if(!mem)
        return MSVCRT_calloc(num, size);

    size = num*size;
    old_size = _msize(mem);

    ret = MSVCRT_realloc(mem, size);
    if(!ret) {
        *MSVCRT__errno() = MSVCRT_ENOMEM;
        return NULL;
    }

    if(size>old_size)
        memset((BYTE*)ret+old_size, 0, size-old_size);
    return ret;
}

453 454 455
/*********************************************************************
 *		__p__amblksiz (MSVCRT.@)
 */
456
unsigned int* CDECL __p__amblksiz(void)
457 458 459
{
  return &MSVCRT_amblksiz;
}
460 461 462 463

/*********************************************************************
 *		_get_sbh_threshold (MSVCRT.@)
 */
464
MSVCRT_size_t CDECL _get_sbh_threshold(void)
465 466 467 468 469 470 471
{
  return MSVCRT_sbh_threshold;
}

/*********************************************************************
 *		_set_sbh_threshold (MSVCRT.@)
 */
472
int CDECL _set_sbh_threshold(MSVCRT_size_t threshold)
473
{
474 475 476
#ifdef _WIN64
  return 0;
#else
477 478
  if(threshold > 1016)
     return 0;
479 480 481 482 483 484 485 486 487

  if(!sb_heap)
  {
      sb_heap = HeapCreate(0, 0, 0);
      if(!sb_heap)
          return 0;
  }

  MSVCRT_sbh_threshold = (threshold+0xf) & ~0xf;
488
  return 1;
489
#endif
490
}
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508

/*********************************************************************
 *		_aligned_free (MSVCRT.@)
 */
void CDECL _aligned_free(void *memblock)
{
    TRACE("(%p)\n", memblock);

    if (memblock)
    {
        void **saved = SAVED_PTR(memblock);
        MSVCRT_free(*saved);
    }
}

/*********************************************************************
 *		_aligned_offset_malloc (MSVCRT.@)
 */
509
void * CDECL _aligned_offset_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment, MSVCRT_size_t offset)
510 511
{
    void *memblock, *temp, **saved;
512
    TRACE("(%lu, %lu, %lu)\n", size, alignment, offset);
513 514 515 516

    /* alignment must be a power of 2 */
    if ((alignment & (alignment - 1)) != 0)
    {
517
        *MSVCRT__errno() = MSVCRT_EINVAL;
518 519 520 521
        return NULL;
    }

    /* offset must be less than size */
522
    if (offset && offset >= size)
523
    {
524
        *MSVCRT__errno() = MSVCRT_EINVAL;
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
        return NULL;
    }

    /* don't align to less than void pointer size */
    if (alignment < sizeof(void *))
        alignment = sizeof(void *);

    /* allocate enough space for void pointer and alignment */
    temp = MSVCRT_malloc(size + alignment + sizeof(void *));

    if (!temp)
        return NULL;

    /* adjust pointer for proper alignment and offset */
    memblock = ALIGN_PTR(temp, alignment, offset);

    /* Save the real allocation address below returned address */
    /* so it can be found later to free. */
    saved = SAVED_PTR(memblock);
    *saved = temp;

    return memblock;
}

/*********************************************************************
 *		_aligned_malloc (MSVCRT.@)
 */
552
void * CDECL _aligned_malloc(MSVCRT_size_t size, MSVCRT_size_t alignment)
553
{
554
    TRACE("(%lu, %lu)\n", size, alignment);
555 556 557 558 559 560
    return _aligned_offset_malloc(size, alignment, 0);
}

/*********************************************************************
 *		_aligned_offset_realloc (MSVCRT.@)
 */
561 562
void * CDECL _aligned_offset_realloc(void *memblock, MSVCRT_size_t size,
                                     MSVCRT_size_t alignment, MSVCRT_size_t offset)
563 564
{
    void * temp, **saved;
565
    MSVCRT_size_t old_padding, new_padding, old_size;
566
    TRACE("(%p, %lu, %lu, %lu)\n", memblock, size, alignment, offset);
567 568 569 570 571 572 573

    if (!memblock)
        return _aligned_offset_malloc(size, alignment, offset);

    /* alignment must be a power of 2 */
    if ((alignment & (alignment - 1)) != 0)
    {
574
        *MSVCRT__errno() = MSVCRT_EINVAL;
575 576 577 578 579 580
        return NULL;
    }

    /* offset must be less than size */
    if (offset >= size)
    {
581
        *MSVCRT__errno() = MSVCRT_EINVAL;
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
        return NULL;
    }

    if (size == 0)
    {
        _aligned_free(memblock);
        return NULL;
    }

    /* don't align to less than void pointer size */
    if (alignment < sizeof(void *))
        alignment = sizeof(void *);

    /* make sure alignment and offset didn't change */
    saved = SAVED_PTR(memblock);
    if (memblock != ALIGN_PTR(*saved, alignment, offset))
    {
599
        *MSVCRT__errno() = MSVCRT_EINVAL;
600 601 602
        return NULL;
    }

603 604 605 606 607 608 609 610 611
    old_padding = (char *)memblock - (char *)*saved;

    /* Get previous size of block */
    old_size = _msize(*saved);
    if (old_size == -1)
    {
        /* It seems this function was called with an invalid pointer. Bail out. */
        return NULL;
    }
612

613
    /* Adjust old_size to get amount of actual data in old block. */
614
    if (old_size < old_padding)
615 616 617 618
    {
        /* Shouldn't happen. Something's weird, so bail out. */
        return NULL;
    }
619
    old_size -= old_padding;
620 621 622 623 624 625 626 627 628 629 630 631 632

    temp = MSVCRT_realloc(*saved, size + alignment + sizeof(void *));

    if (!temp)
        return NULL;

    /* adjust pointer for proper alignment and offset */
    memblock = ALIGN_PTR(temp, alignment, offset);

    /* Save the real allocation address below returned address */
    /* so it can be found later to free. */
    saved = SAVED_PTR(memblock);

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
    new_padding = (char *)memblock - (char *)temp;

/*
   Memory layout of old block is as follows:
   +-------+---------------------+-+--------------------------+-----------+
   |  ...  | "old_padding" bytes | | ... "old_size" bytes ... |    ...    |
   +-------+---------------------+-+--------------------------+-----------+
           ^                     ^ ^
           |                     | |
        *saved               saved memblock

   Memory layout of new block is as follows:
   +-------+-----------------------------+-+----------------------+-------+
   |  ...  |    "new_padding" bytes      | | ... "size" bytes ... |  ...  |
   +-------+-----------------------------+-+----------------------+-------+
           ^                             ^ ^
           |                             | |
          temp                       saved memblock

   However, in the new block, actual data is still written as follows
   (because it was copied by MSVCRT_realloc):
   +-------+---------------------+--------------------------------+-------+
   |  ...  | "old_padding" bytes |   ... "old_size" bytes ...     |  ...  |
   +-------+---------------------+--------------------------------+-------+
           ^                             ^ ^
           |                             | |
          temp                       saved memblock

   Therefore, min(old_size,size) bytes of actual data have to be moved
   from the offset they were at in the old block (temp + old_padding),
   to the offset they have to be in the new block (temp + new_padding == memblock).
*/
665
    if (new_padding != old_padding)
666
        memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
667 668 669 670 671 672 673 674 675

    *saved = temp;

    return memblock;
}

/*********************************************************************
 *		_aligned_realloc (MSVCRT.@)
 */
676
void * CDECL _aligned_realloc(void *memblock, MSVCRT_size_t size, MSVCRT_size_t alignment)
677
{
678
    TRACE("(%p, %lu, %lu)\n", memblock, size, alignment);
679 680
    return _aligned_offset_realloc(memblock, size, alignment, 0);
}
681 682 683 684

/*********************************************************************
 *		memmove_s (MSVCRT.@)
 */
685
int CDECL MSVCRT_memmove_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
686 687 688 689 690 691
{
    TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);

    if(!count)
        return 0;

692 693 694
    if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE )) return MSVCRT_ERANGE;
695

696 697 698 699
    memmove(dest, src, count);
    return 0;
}

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
/*********************************************************************
 *              wmemmove_s (MSVCR100.@)
 */
int CDECL wmemmove_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
        const MSVCRT_wchar_t *src, MSVCRT_size_t count)
{
    TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);

    if (!count)
        return 0;

    /* Native does not seem to conform to 6.7.1.2.3 in
     * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf
     * in that it does not zero the output buffer on constraint violation.
     */
    if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) return MSVCRT_ERANGE;

    memmove(dest, src, sizeof(MSVCRT_wchar_t)*count);
    return 0;
}

723 724 725
/*********************************************************************
 *		memcpy_s (MSVCRT.@)
 */
726
int CDECL MSVCRT_memcpy_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
727 728 729 730 731 732 733 734 735 736
{
    TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);

    if(!count)
        return 0;

    if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT(src != NULL))
    {
        memset(dest, 0, numberOfElements);
737 738
        return MSVCRT_EINVAL;
    }
739 740
    if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE ))
    {
741 742 743 744
        memset(dest, 0, numberOfElements);
        return MSVCRT_ERANGE;
    }

745
    memcpy(dest, src, count);
746 747
    return 0;
}
748

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
/*********************************************************************
 *              wmemcpy_s (MSVCR100.@)
 */
int CDECL wmemcpy_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements,
        const MSVCRT_wchar_t *src, MSVCRT_size_t count)
{
    TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);

    if (!count)
        return 0;

    if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;

    if (!MSVCRT_CHECK_PMT(src != NULL)) {
        memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
        return MSVCRT_EINVAL;
    }
    if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) {
        memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t));
        return MSVCRT_ERANGE;
    }

    memcpy(dest, src, sizeof(MSVCRT_wchar_t)*count);
    return 0;
}

775 776 777
/*********************************************************************
 *		strncpy_s (MSVCRT.@)
 */
778
int CDECL MSVCRT_strncpy_s(char *dest, MSVCRT_size_t numberOfElements,
779 780 781 782
        const char *src, MSVCRT_size_t count)
{
    MSVCRT_size_t i, end;

783
    TRACE("(%p %lu %s %lu)\n", dest, numberOfElements, debugstr_a(src), count);
784

785 786 787
    if(!count) {
        if(dest && numberOfElements)
            *dest = 0;
788
        return 0;
789
    }
790

791 792 793
    if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL;
    if (!MSVCRT_CHECK_PMT(numberOfElements != 0)) return MSVCRT_EINVAL;
794

795
    if(count!=MSVCRT__TRUNCATE && count<numberOfElements)
796 797 798 799 800 801 802
        end = count;
    else
        end = numberOfElements-1;

    for(i=0; i<end && src[i]; i++)
        dest[i] = src[i];

803
    if(!src[i] || end==count || count==MSVCRT__TRUNCATE) {
804 805 806 807
        dest[i] = '\0';
        return 0;
    }

808
    MSVCRT_INVALID_PMT("dest[numberOfElements] is too small", MSVCRT_EINVAL);
809 810 811
    dest[0] = '\0';
    return MSVCRT_EINVAL;
}
812 813 814 815 816 817 818 819 820 821

BOOL msvcrt_init_heap(void)
{
    heap = HeapCreate(0, 0, 0);
    return heap != NULL;
}

void msvcrt_destroy_heap(void)
{
    HeapDestroy(heap);
822 823
    if(sb_heap)
        HeapDestroy(sb_heap);
824
}