//------------------------------------------------------------------------ // ArenaAllocator::alloateMemory: // Allocates memory using an `ArenaAllocator`. // // Arguments: // size - The number of bytes to allocate. // // Return Value: // A pointer to the allocated memory. // // Note: // This is the DEBUG-only version of `allocateMemory`; the release // version of this method is defined in the corresponding header file. // This version of the method has some abilities that the release // version does not: it may inject faults into the allocator and // seeds all allocations with a specified pattern to help catch // use-before-init problems. void* ArenaAllocator::allocateMemory(size_t size) { assert(size != 0 && (size & (sizeof(int) - 1)) == 0); // Ensure that we always allocate in pointer sized increments. size = (size_t)roundUp(size, sizeof(size_t)); if (JitConfig.ShouldInjectFault() != 0) { // Force the underlying memory allocator (either the OS or the CLR hoster) // to allocate the memory. Any fault injection will kick in. void* p = ClrAllocInProcessHeap(0, S_SIZE_T(1)); if (p != nullptr) { ClrFreeInProcessHeap(0, p); } else { NOMEM(); // Throw! } } void* block = m_nextFreeByte; m_nextFreeByte += size; if (m_nextFreeByte > m_lastFreeByte) { block = allocateNewPage(size); } memset(block, UninitializedWord<char>(), size); return block; }
//------------------------------------------------------------------------ // ArenaAllocator::freeHostMemory: // Frees memory allocated by a previous call to `allocateHostMemory`. // // Arguments: // block - A pointer to the memory to free. void ArenaAllocator::freeHostMemory(void* block) { #if defined(DEBUG) if (bypassHostAllocator()) { ::HeapFree(GetProcessHeap(), 0, block); } else { ClrFreeInProcessHeap(0, block); } #else // defined(DEBUG) m_memoryManager->ClrVirtualFree(block, 0, MEM_RELEASE); #endif // !defined(DEBUG) }
// Free a packet allocated with DbgAlloc. void __stdcall DbgFree(void *b, void **ppvCallstack, BOOL isArray) { SCAN_IGNORE_FAULT; // tell the static contract analysis tool to ignore FAULTS due to calls of 'new' in code called by this function STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_DEBUG_ONLY; if (!g_DbgEnabled) { if (b) // check for null pointer Win98 doesn't like being // called to free null pointers. ClrFreeInProcessHeap(0, b); return; } // Technically it's possible to get here without having gone through // DbgAlloc (since it's legal to deallocate a NULL pointer), so we // better check for initializtion to be on the safe side. if (!g_HeapInitialized) DbgAllocInit(); CDA_LOCK(); // Check all active packets still look OK. if (g_ConstantRecheck) DbgValidateActivePackets(NULL, NULL); // Count this call to DbgFree. CDA_STATS_INC(Frees); if (b == NULL) { CDA_STATS_INC(NullFrees); CDA_UNLOCK(); return; } // Locate the packet header in front of the data packet. DbgAllocHeader *h = CDA_DATA_TO_HEADER(b); // Verify not calling delete [] on new, and vice versa //_ASSERTE (h->m_IsArray == isArray); // Check that the header looks OK. DbgValidateHeader(h); // Count the total number of bytes we've freed so far. CDA_STATS_ADD(FreeBytes, h->m_Length); // Unlink the packet from the live packet queue. if (h->m_Prev) h->m_Prev->m_Next = h->m_Next; else g_AllocListFirst = h->m_Next; if (h->m_Next) h->m_Next->m_Prev = h->m_Prev; else g_AllocListLast = h->m_Prev; // Zap our link pointers so we'll spot corruption sooner. h->m_Next = (DbgAllocHeader *)(UINT_PTR)CDA_INV_PATTERN; h->m_Prev = (DbgAllocHeader *)(UINT_PTR)CDA_INV_PATTERN; // Zap the tag fields in the header so we'll spot double deallocations // straight away. h->m_Magic1 = CDA_INV_PATTERN; *CDA_MAGIC2(h) = CDA_INV_PATTERN; // Poison the user's data area so that continued access to it after the // deallocation will likely cause an assertion that much sooner. if (g_PoisonPackets) memset(b, CDA_DEALLOC_PATTERN, h->m_Length); // Record the callstack of the deallocator (handy for debugging double // deallocation problems). for (unsigned i = 0; i < g_CallStackDepth; i++) CDA_DEALLOC_STACK(h, i) = ppvCallstack[i]; // put the pack on the free list for a while. Delete the one that it replaces. if (g_PoisonPackets) { DbgAllocHeader* tmp = g_AllocFreeQueue[g_AllocFreeQueueCur]; g_AllocFreeQueue[g_AllocFreeQueueCur] = h; h = tmp; g_AllocFreeQueueCur++; if (g_AllocFreeQueueCur >= g_FreeQueueSize) g_AllocFreeQueueCur = 0; } CDA_UNLOCK(); if (h) { if (g_PagePerAlloc) { // In page per alloc mode we decommit the pages allocated, but leave // them reserved so that we never reuse the same virtual addresses. ClrVirtualFree(h, h->m_Length + CDA_SIZEOF_HEADER() + CDA_OPT_GUARD_BYTES, MEM_DECOMMIT); } else ClrHeapFree(g_HeapHandle, 0, h); } }