Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenheap.c
Go to the documentation of this file.
00001 /* 00002 * msvcrt.dll heap functions 00003 * 00004 * Copyright 2000 Jon Griffiths 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 * 00020 * Note: Win32 heap operations are MT safe. We only lock the new 00021 * handler and non atomic heap operations 00022 */ 00023 00024 #include <precomp.h> 00025 #include <malloc.h> 00026 00027 /* MT */ 00028 #define LOCK_HEAP _mlock( _HEAP_LOCK ) 00029 #define UNLOCK_HEAP _munlock( _HEAP_LOCK ) 00030 00031 /* _aligned */ 00032 #define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \ 00033 ~(sizeof(void *) - 1))) 00034 #define ALIGN_PTR(ptr, alignment, offset) ((void *) \ 00035 ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \ 00036 ~(alignment - 1)) - offset)) 00037 00038 00039 typedef int (CDECL *MSVCRT_new_handler_func)(size_t size); 00040 00041 static MSVCRT_new_handler_func MSVCRT_new_handler; 00042 static int MSVCRT_new_mode; 00043 00044 /* FIXME - According to documentation it should be 8*1024, at runtime it returns 16 */ 00045 static unsigned int MSVCRT_amblksiz = 16; 00046 /* FIXME - According to documentation it should be 480 bytes, at runtime default is 0 */ 00047 static size_t MSVCRT_sbh_threshold = 0; 00048 00049 /********************************************************************* 00050 * ??2@YAPAXI@Z (MSVCRT.@) 00051 */ 00052 void* CDECL MSVCRT_operator_new(size_t size) 00053 { 00054 void *retval; 00055 int freed; 00056 00057 do 00058 { 00059 retval = HeapAlloc(GetProcessHeap(), 0, size); 00060 if(retval) 00061 { 00062 TRACE("(%ld) returning %p\n", size, retval); 00063 return retval; 00064 } 00065 00066 LOCK_HEAP; 00067 if(MSVCRT_new_handler) 00068 freed = (*MSVCRT_new_handler)(size); 00069 else 00070 freed = 0; 00071 UNLOCK_HEAP; 00072 } while(freed); 00073 00074 TRACE("(%ld) out of memory\n", size); 00075 return NULL; 00076 } 00077 00078 00079 /********************************************************************* 00080 * ??2@YAPAXIHPBDH@Z (MSVCRT.@) 00081 */ 00082 void* CDECL MSVCRT_operator_new_dbg(size_t size, int type, const char *file, int line) 00083 { 00084 return MSVCRT_operator_new( size ); 00085 } 00086 00087 00088 /********************************************************************* 00089 * ??3@YAXPAX@Z (MSVCRT.@) 00090 */ 00091 void CDECL MSVCRT_operator_delete(void *mem) 00092 { 00093 TRACE("(%p)\n", mem); 00094 HeapFree(GetProcessHeap(), 0, mem); 00095 } 00096 00097 00098 /********************************************************************* 00099 * ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@) 00100 */ 00101 MSVCRT_new_handler_func CDECL MSVCRT__query_new_handler(void) 00102 { 00103 return MSVCRT_new_handler; 00104 } 00105 00106 00107 /********************************************************************* 00108 * ?_query_new_mode@@YAHXZ (MSVCRT.@) 00109 */ 00110 int CDECL MSVCRT__query_new_mode(void) 00111 { 00112 return MSVCRT_new_mode; 00113 } 00114 00115 /********************************************************************* 00116 * ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@) 00117 */ 00118 MSVCRT_new_handler_func CDECL MSVCRT__set_new_handler(MSVCRT_new_handler_func func) 00119 { 00120 MSVCRT_new_handler_func old_handler; 00121 LOCK_HEAP; 00122 old_handler = MSVCRT_new_handler; 00123 MSVCRT_new_handler = func; 00124 UNLOCK_HEAP; 00125 return old_handler; 00126 } 00127 00128 /********************************************************************* 00129 * ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) 00130 */ 00131 MSVCRT_new_handler_func CDECL MSVCRT_set_new_handler(void *func) 00132 { 00133 TRACE("(%p)\n",func); 00134 MSVCRT__set_new_handler(NULL); 00135 return NULL; 00136 } 00137 00138 /********************************************************************* 00139 * ?_set_new_mode@@YAHH@Z (MSVCRT.@) 00140 */ 00141 int CDECL MSVCRT__set_new_mode(int mode) 00142 { 00143 int old_mode; 00144 LOCK_HEAP; 00145 old_mode = MSVCRT_new_mode; 00146 MSVCRT_new_mode = mode; 00147 UNLOCK_HEAP; 00148 return old_mode; 00149 } 00150 00151 /********************************************************************* 00152 * _callnewh (MSVCRT.@) 00153 */ 00154 int CDECL _callnewh(size_t size) 00155 { 00156 if(MSVCRT_new_handler) 00157 (*MSVCRT_new_handler)(size); 00158 return 0; 00159 } 00160 00161 /********************************************************************* 00162 * _expand (MSVCRT.@) 00163 */ 00164 void* CDECL _expand(void* mem, size_t size) 00165 { 00166 return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size); 00167 } 00168 00169 /********************************************************************* 00170 * _heapchk (MSVCRT.@) 00171 */ 00172 int CDECL _heapchk(void) 00173 { 00174 if (!HeapValidate( GetProcessHeap(), 0, NULL)) 00175 { 00176 _dosmaperr(GetLastError()); 00177 return _HEAPBADNODE; 00178 } 00179 return _HEAPOK; 00180 } 00181 00182 /********************************************************************* 00183 * _heapmin (MSVCRT.@) 00184 */ 00185 int CDECL _heapmin(void) 00186 { 00187 if (!HeapCompact( GetProcessHeap(), 0 )) 00188 { 00189 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 00190 _dosmaperr(GetLastError()); 00191 return -1; 00192 } 00193 return 0; 00194 } 00195 00196 /********************************************************************* 00197 * _heapwalk (MSVCRT.@) 00198 */ 00199 int CDECL _heapwalk(_HEAPINFO* next) 00200 { 00201 PROCESS_HEAP_ENTRY phe; 00202 00203 LOCK_HEAP; 00204 phe.lpData = next->_pentry; 00205 phe.cbData = (DWORD)next->_size; 00206 phe.wFlags = next->_useflag == _USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0; 00207 00208 if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY && 00209 !HeapValidate( GetProcessHeap(), 0, phe.lpData )) 00210 { 00211 UNLOCK_HEAP; 00212 _dosmaperr(GetLastError()); 00213 return _HEAPBADNODE; 00214 } 00215 00216 do 00217 { 00218 if (!HeapWalk( GetProcessHeap(), &phe )) 00219 { 00220 UNLOCK_HEAP; 00221 if (GetLastError() == ERROR_NO_MORE_ITEMS) 00222 return _HEAPEND; 00223 _dosmaperr(GetLastError()); 00224 if (!phe.lpData) 00225 return _HEAPBADBEGIN; 00226 return _HEAPBADNODE; 00227 } 00228 } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE)); 00229 00230 UNLOCK_HEAP; 00231 next->_pentry = phe.lpData; 00232 next->_size = phe.cbData; 00233 next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? _USEDENTRY : _FREEENTRY; 00234 return _HEAPOK; 00235 } 00236 00237 /********************************************************************* 00238 * _heapset (MSVCRT.@) 00239 */ 00240 int CDECL _heapset(unsigned int value) 00241 { 00242 int retval; 00243 _HEAPINFO heap; 00244 00245 memset( &heap, 0, sizeof(heap) ); 00246 LOCK_HEAP; 00247 while ((retval = _heapwalk(&heap)) == _HEAPOK) 00248 { 00249 if (heap._useflag == _FREEENTRY) 00250 memset(heap._pentry, value, heap._size); 00251 } 00252 UNLOCK_HEAP; 00253 return retval == _HEAPEND? _HEAPOK : retval; 00254 } 00255 00256 /********************************************************************* 00257 * _heapadd (MSVCRT.@) 00258 */ 00259 int CDECL _heapadd(void* mem, size_t size) 00260 { 00261 TRACE("(%p,%ld) unsupported in Win32\n", mem,size); 00262 *_errno() = ENOSYS; 00263 return -1; 00264 } 00265 00266 /********************************************************************* 00267 * _heapadd (MSVCRT.@) 00268 */ 00269 intptr_t CDECL _get_heap_handle(void) 00270 { 00271 return (intptr_t)GetProcessHeap(); 00272 } 00273 00274 /********************************************************************* 00275 * _msize (MSVCRT.@) 00276 */ 00277 size_t CDECL _msize(void* mem) 00278 { 00279 size_t size = HeapSize(GetProcessHeap(),0,mem); 00280 if (size == ~(size_t)0) 00281 { 00282 WARN(":Probably called with non wine-allocated memory, ret = -1\n"); 00283 /* At least the Win32 crtdll/msvcrt also return -1 in this case */ 00284 } 00285 return size; 00286 } 00287 00288 /********************************************************************* 00289 * calloc (MSVCRT.@) 00290 */ 00291 void* CDECL calloc(size_t size, size_t count) 00292 { 00293 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); 00294 } 00295 00296 /********************************************************************* 00297 * free (MSVCRT.@) 00298 */ 00299 void CDECL free(void* ptr) 00300 { 00301 if(ptr == NULL) return; 00302 HeapFree(GetProcessHeap(),0,ptr); 00303 } 00304 00305 /********************************************************************* 00306 * malloc (MSVCRT.@) 00307 */ 00308 void* CDECL malloc(size_t size) 00309 { 00310 void *ret = HeapAlloc(GetProcessHeap(),0,size); 00311 if (!ret) 00312 *_errno() = ENOMEM; 00313 return ret; 00314 } 00315 00316 /********************************************************************* 00317 * realloc (MSVCRT.@) 00318 */ 00319 void* CDECL realloc(void* ptr, size_t size) 00320 { 00321 if (!ptr) return malloc(size); 00322 if (size) return HeapReAlloc(GetProcessHeap(), 0, ptr, size); 00323 free(ptr); 00324 return NULL; 00325 } 00326 00327 /********************************************************************* 00328 * __p__amblksiz (MSVCRT.@) 00329 */ 00330 unsigned int* CDECL __p__amblksiz(void) 00331 { 00332 return &MSVCRT_amblksiz; 00333 } 00334 00335 /********************************************************************* 00336 * _get_sbh_threshold (MSVCRT.@) 00337 */ 00338 size_t CDECL _get_sbh_threshold(void) 00339 { 00340 return MSVCRT_sbh_threshold; 00341 } 00342 00343 /********************************************************************* 00344 * _set_sbh_threshold (MSVCRT.@) 00345 */ 00346 int CDECL _set_sbh_threshold(size_t threshold) 00347 { 00348 if(threshold > 1016) 00349 return 0; 00350 else 00351 MSVCRT_sbh_threshold = threshold; 00352 return 1; 00353 } 00354 00355 /********************************************************************* 00356 * _aligned_free (MSVCRT.@) 00357 */ 00358 void CDECL _aligned_free(void *memblock) 00359 { 00360 TRACE("(%p)\n", memblock); 00361 00362 if (memblock) 00363 { 00364 void **saved = SAVED_PTR(memblock); 00365 free(*saved); 00366 } 00367 } 00368 00369 /********************************************************************* 00370 * _aligned_offset_malloc (MSVCRT.@) 00371 */ 00372 void * CDECL _aligned_offset_malloc(size_t size, size_t alignment, size_t offset) 00373 { 00374 void *memblock, *temp, **saved; 00375 TRACE("(%lu, %lu, %lu)\n", size, alignment, offset); 00376 00377 /* alignment must be a power of 2 */ 00378 if ((alignment & (alignment - 1)) != 0) 00379 { 00380 *_errno() = EINVAL; 00381 return NULL; 00382 } 00383 00384 /* offset must be less than size */ 00385 if (offset >= size) 00386 { 00387 *_errno() = EINVAL; 00388 return NULL; 00389 } 00390 00391 /* don't align to less than void pointer size */ 00392 if (alignment < sizeof(void *)) 00393 alignment = sizeof(void *); 00394 00395 /* allocate enough space for void pointer and alignment */ 00396 temp = malloc(size + alignment + sizeof(void *)); 00397 00398 if (!temp) 00399 return NULL; 00400 00401 /* adjust pointer for proper alignment and offset */ 00402 memblock = ALIGN_PTR(temp, alignment, offset); 00403 00404 /* Save the real allocation address below returned address */ 00405 /* so it can be found later to free. */ 00406 saved = SAVED_PTR(memblock); 00407 *saved = temp; 00408 00409 return memblock; 00410 } 00411 00412 /********************************************************************* 00413 * _aligned_malloc (MSVCRT.@) 00414 */ 00415 void * CDECL _aligned_malloc(size_t size, size_t alignment) 00416 { 00417 TRACE("(%lu, %lu)\n", size, alignment); 00418 return _aligned_offset_malloc(size, alignment, 0); 00419 } 00420 00421 /********************************************************************* 00422 * _aligned_offset_realloc (MSVCRT.@) 00423 */ 00424 void * CDECL _aligned_offset_realloc(void *memblock, size_t size, 00425 size_t alignment, size_t offset) 00426 { 00427 void * temp, **saved; 00428 size_t old_padding, new_padding, old_size; 00429 TRACE("(%p, %lu, %lu, %lu)\n", memblock, size, alignment, offset); 00430 00431 if (!memblock) 00432 return _aligned_offset_malloc(size, alignment, offset); 00433 00434 /* alignment must be a power of 2 */ 00435 if ((alignment & (alignment - 1)) != 0) 00436 { 00437 *_errno() = EINVAL; 00438 return NULL; 00439 } 00440 00441 /* offset must be less than size */ 00442 if (offset >= size) 00443 { 00444 *_errno() = EINVAL; 00445 return NULL; 00446 } 00447 00448 if (size == 0) 00449 { 00450 _aligned_free(memblock); 00451 return NULL; 00452 } 00453 00454 /* don't align to less than void pointer size */ 00455 if (alignment < sizeof(void *)) 00456 alignment = sizeof(void *); 00457 00458 /* make sure alignment and offset didn't change */ 00459 saved = SAVED_PTR(memblock); 00460 if (memblock != ALIGN_PTR(*saved, alignment, offset)) 00461 { 00462 *_errno() = EINVAL; 00463 return NULL; 00464 } 00465 00466 old_padding = (char *)memblock - (char *)*saved; 00467 00468 /* Get previous size of block */ 00469 old_size = _msize(*saved); 00470 if (old_size == -1) 00471 { 00472 /* It seems this function was called with an invalid pointer. Bail out. */ 00473 return NULL; 00474 } 00475 00476 /* Adjust old_size to get amount of actual data in old block. */ 00477 if (old_size < old_padding) 00478 { 00479 /* Shouldn't happen. Something's weird, so bail out. */ 00480 return NULL; 00481 } 00482 old_size -= old_padding; 00483 00484 temp = realloc(*saved, size + alignment + sizeof(void *)); 00485 00486 if (!temp) 00487 return NULL; 00488 00489 /* adjust pointer for proper alignment and offset */ 00490 memblock = ALIGN_PTR(temp, alignment, offset); 00491 00492 /* Save the real allocation address below returned address */ 00493 /* so it can be found later to free. */ 00494 saved = SAVED_PTR(memblock); 00495 00496 new_padding = (char *)memblock - (char *)temp; 00497 00498 /* 00499 Memory layout of old block is as follows: 00500 +-------+---------------------+-+--------------------------+-----------+ 00501 | ... | "old_padding" bytes | | ... "old_size" bytes ... | ... | 00502 +-------+---------------------+-+--------------------------+-----------+ 00503 ^ ^ ^ 00504 | | | 00505 *saved saved memblock 00506 00507 Memory layout of new block is as follows: 00508 +-------+-----------------------------+-+----------------------+-------+ 00509 | ... | "new_padding" bytes | | ... "size" bytes ... | ... | 00510 +-------+-----------------------------+-+----------------------+-------+ 00511 ^ ^ ^ 00512 | | | 00513 temp saved memblock 00514 00515 However, in the new block, actual data is still written as follows 00516 (because it was copied by MSVCRT_realloc): 00517 +-------+---------------------+--------------------------------+-------+ 00518 | ... | "old_padding" bytes | ... "old_size" bytes ... | ... | 00519 +-------+---------------------+--------------------------------+-------+ 00520 ^ ^ ^ 00521 | | | 00522 temp saved memblock 00523 00524 Therefore, min(old_size,size) bytes of actual data have to be moved 00525 from the offset they were at in the old block (temp + old_padding), 00526 to the offset they have to be in the new block (temp + new_padding == memblock). 00527 */ 00528 if (new_padding != old_padding) 00529 memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size); 00530 00531 *saved = temp; 00532 00533 return memblock; 00534 } 00535 00536 /********************************************************************* 00537 * _aligned_realloc (MSVCRT.@) 00538 */ 00539 void * CDECL _aligned_realloc(void *memblock, size_t size, size_t alignment) 00540 { 00541 TRACE("(%p, %lu, %lu)\n", memblock, size, alignment); 00542 return _aligned_offset_realloc(memblock, size, alignment, 0); 00543 } 00544 00545 /********************************************************************* 00546 * memmove_s (MSVCRT.@) 00547 */ 00548 int CDECL memmove_s(void *dest, size_t numberOfElements, const void *src, size_t count) 00549 { 00550 TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count); 00551 00552 if(!count) 00553 return 0; 00554 00555 if(!dest || !src) { 00556 if(dest) 00557 memset(dest, 0, numberOfElements); 00558 00559 *_errno() = EINVAL; 00560 return EINVAL; 00561 } 00562 00563 if(count > numberOfElements) { 00564 memset(dest, 0, numberOfElements); 00565 00566 *_errno() = ERANGE; 00567 return ERANGE; 00568 } 00569 00570 memmove(dest, src, count); 00571 return 0; 00572 } 00573 00574 /********************************************************************* 00575 * strncpy_s (MSVCRT.@) 00576 */ 00577 int CDECL strncpy_s(char *dest, size_t numberOfElements, 00578 const char *src, size_t count) 00579 { 00580 size_t i, end; 00581 00582 TRACE("(%s %lu %s %lu)\n", dest, numberOfElements, src, count); 00583 00584 if(!count) 00585 return 0; 00586 00587 if (!MSVCRT_CHECK_PMT(dest != NULL) || !MSVCRT_CHECK_PMT(src != NULL) || 00588 !MSVCRT_CHECK_PMT(numberOfElements != 0)) { 00589 *_errno() = EINVAL; 00590 return EINVAL; 00591 } 00592 00593 if(count!=_TRUNCATE && count<numberOfElements) 00594 end = count; 00595 else 00596 end = numberOfElements-1; 00597 00598 for(i=0; i<end && src[i]; i++) 00599 dest[i] = src[i]; 00600 00601 if(!src[i] || end==count || count==_TRUNCATE) { 00602 dest[i] = '\0'; 00603 return 0; 00604 } 00605 00606 MSVCRT_INVALID_PMT("dest[numberOfElements] is too small"); 00607 dest[0] = '\0'; 00608 *_errno() = EINVAL; 00609 return EINVAL; 00610 } Generated on Sun May 27 2012 04:19:17 for ReactOS by
1.7.6.1
|