| /* |
| * msvcrt.dll heap functions |
| * |
| * Copyright 2000 Jon Griffiths |
| * |
| * 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 |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * Note: Win32 heap operations are MT safe. We only lock the new |
| * handler and non atomic heap operations |
| */ |
| |
| #include "msvcrt.h" |
| #include "ms_errno.h" |
| |
| #include "msvcrt/malloc.h" |
| #include "msvcrt/stdlib.h" |
| #include "mtdll.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); |
| |
| /* MT */ |
| #define LOCK_HEAP _mlock( _HEAP_LOCK ) |
| #define UNLOCK_HEAP _munlock( _HEAP_LOCK ) |
| |
| |
| typedef void (*MSVCRT_new_handler_func)(unsigned long size); |
| |
| static MSVCRT_new_handler_func MSVCRT_new_handler; |
| static int MSVCRT_new_mode; |
| |
| |
| /********************************************************************* |
| * ??2@YAPAXI@Z (MSVCRT.@) |
| */ |
| void* MSVCRT_operator_new(unsigned long size) |
| { |
| void *retval = HeapAlloc(GetProcessHeap(), 0, size); |
| TRACE("(%ld) returning %p\n", size, retval); |
| LOCK_HEAP; |
| if(!retval && MSVCRT_new_handler) |
| (*MSVCRT_new_handler)(size); |
| UNLOCK_HEAP; |
| return retval; |
| } |
| |
| /********************************************************************* |
| * ??3@YAXPAX@Z (MSVCRT.@) |
| */ |
| void MSVCRT_operator_delete(void *mem) |
| { |
| TRACE("(%p)\n", mem); |
| HeapFree(GetProcessHeap(), 0, mem); |
| } |
| |
| |
| /********************************************************************* |
| * ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@) |
| */ |
| MSVCRT_new_handler_func MSVCRT__query_new_handler(void) |
| { |
| return MSVCRT_new_handler; |
| } |
| |
| |
| /********************************************************************* |
| * ?_query_new_mode@@YAHXZ (MSVCRT.@) |
| */ |
| int MSVCRT__query_new_mode(void) |
| { |
| return MSVCRT_new_mode; |
| } |
| |
| /********************************************************************* |
| * ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@) |
| */ |
| MSVCRT_new_handler_func MSVCRT__set_new_handler(MSVCRT_new_handler_func func) |
| { |
| MSVCRT_new_handler_func old_handler; |
| LOCK_HEAP; |
| old_handler = MSVCRT_new_handler; |
| MSVCRT_new_handler = func; |
| UNLOCK_HEAP; |
| return old_handler; |
| } |
| |
| /********************************************************************* |
| * ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) |
| */ |
| MSVCRT_new_handler_func MSVCRT_set_new_handler(void *func) |
| { |
| TRACE("(%p)\n",func); |
| MSVCRT__set_new_handler(NULL); |
| return NULL; |
| } |
| |
| /********************************************************************* |
| * ?_set_new_mode@@YAHH@Z (MSVCRT.@) |
| */ |
| int MSVCRT__set_new_mode(int mode) |
| { |
| int old_mode; |
| LOCK_HEAP; |
| old_mode = MSVCRT_new_mode; |
| MSVCRT_new_mode = mode; |
| UNLOCK_HEAP; |
| return old_mode; |
| } |
| |
| /********************************************************************* |
| * _callnewh (MSVCRT.@) |
| */ |
| int _callnewh(unsigned long size) |
| { |
| if(MSVCRT_new_handler) |
| (*MSVCRT_new_handler)(size); |
| return 0; |
| } |
| |
| /********************************************************************* |
| * _expand (MSVCRT.@) |
| */ |
| void* _expand(void* mem, MSVCRT_size_t size) |
| { |
| return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size); |
| } |
| |
| /********************************************************************* |
| * _heapchk (MSVCRT.@) |
| */ |
| int _heapchk(void) |
| { |
| if (!HeapValidate( GetProcessHeap(), 0, NULL)) |
| { |
| MSVCRT__set_errno(GetLastError()); |
| return _HEAPBADNODE; |
| } |
| return _HEAPOK; |
| } |
| |
| /********************************************************************* |
| * _heapmin (MSVCRT.@) |
| */ |
| int _heapmin(void) |
| { |
| if (!HeapCompact( GetProcessHeap(), 0 )) |
| { |
| if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) |
| MSVCRT__set_errno(GetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| /********************************************************************* |
| * _heapwalk (MSVCRT.@) |
| */ |
| int _heapwalk(_HEAPINFO* next) |
| { |
| PROCESS_HEAP_ENTRY phe; |
| |
| LOCK_HEAP; |
| phe.lpData = next->_pentry; |
| phe.cbData = next->_size; |
| phe.wFlags = next->_useflag == _USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0; |
| |
| if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY && |
| !HeapValidate( GetProcessHeap(), 0, phe.lpData )) |
| { |
| UNLOCK_HEAP; |
| MSVCRT__set_errno(GetLastError()); |
| return _HEAPBADNODE; |
| } |
| |
| do |
| { |
| if (!HeapWalk( GetProcessHeap(), &phe )) |
| { |
| UNLOCK_HEAP; |
| if (GetLastError() == ERROR_NO_MORE_ITEMS) |
| return _HEAPEND; |
| MSVCRT__set_errno(GetLastError()); |
| if (!phe.lpData) |
| return _HEAPBADBEGIN; |
| return _HEAPBADNODE; |
| } |
| } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE)); |
| |
| UNLOCK_HEAP; |
| next->_pentry = phe.lpData; |
| next->_size = phe.cbData; |
| next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? _USEDENTRY : _FREEENTRY; |
| return _HEAPOK; |
| } |
| |
| /********************************************************************* |
| * _heapset (MSVCRT.@) |
| */ |
| int _heapset(unsigned int value) |
| { |
| int retval; |
| _HEAPINFO heap; |
| |
| memset( &heap, 0, sizeof(_HEAPINFO) ); |
| LOCK_HEAP; |
| while ((retval = _heapwalk(&heap)) == _HEAPOK) |
| { |
| if (heap._useflag == _FREEENTRY) |
| memset(heap._pentry, value, heap._size); |
| } |
| UNLOCK_HEAP; |
| return retval == _HEAPEND? _HEAPOK : retval; |
| } |
| |
| /********************************************************************* |
| * _heapadd (MSVCRT.@) |
| */ |
| int _heapadd(void* mem, MSVCRT_size_t size) |
| { |
| TRACE("(%p,%d) unsupported in Win32\n", mem,size); |
| *MSVCRT__errno() = MSVCRT_ENOSYS; |
| return -1; |
| } |
| |
| /********************************************************************* |
| * _msize (MSVCRT.@) |
| */ |
| MSVCRT_size_t _msize(void* mem) |
| { |
| long size = HeapSize(GetProcessHeap(),0,mem); |
| if (size == -1) |
| { |
| 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; |
| } |
| |
| /********************************************************************* |
| * calloc (MSVCRT.@) |
| */ |
| void* MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count) |
| { |
| return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); |
| } |
| |
| /********************************************************************* |
| * free (MSVCRT.@) |
| */ |
| void MSVCRT_free(void* ptr) |
| { |
| HeapFree(GetProcessHeap(),0,ptr); |
| } |
| |
| /********************************************************************* |
| * malloc (MSVCRT.@) |
| */ |
| void* MSVCRT_malloc(MSVCRT_size_t size) |
| { |
| void *ret = HeapAlloc(GetProcessHeap(),0,size); |
| if (!ret) |
| MSVCRT__set_errno(GetLastError()); |
| return ret; |
| } |
| |
| /********************************************************************* |
| * realloc (MSVCRT.@) |
| */ |
| void* MSVCRT_realloc(void* ptr, MSVCRT_size_t size) |
| { |
| return HeapReAlloc(GetProcessHeap(), 0, ptr, size); |
| } |