alloc-ef.cpp revision 9d577a7b721cf6430727d2bc2577642310642366
/* $Id$ */
/** @file
* IPRT - Memory Allocation, electric fence.
*/
/*
* Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "alloc-ef.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
/*******************************************************************************
* Global Variables *
*******************************************************************************/
#ifdef RTALLOC_EFENCE_TRACE
/** Spinlock protecting the allthe blocks globals. */
static volatile uint32_t g_BlocksLock;
/** Tree tracking the allocations. */
static AVLPVTREE g_BlocksTree;
#ifdef RTALLOC_EFENCE_FREE_DELAYED
/** Tail of the delayed blocks. */
static volatile PRTMEMBLOCK g_pBlocksDelayHead;
/** Tail of the delayed blocks. */
static volatile PRTMEMBLOCK g_pBlocksDelayTail;
/** Number of bytes in the delay list (includes fences). */
static volatile size_t g_cbBlocksDelay;
#endif
#endif
/** Array of pointers free watches for. */
/** Enable logging of all freed memory. */
bool gfRTMemFreeLog = false;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Complains about something.
*/
{
}
/**
* Log an event.
*/
{
#if 0
#endif
}
#ifdef RTALLOC_EFENCE_TRACE
/**
* Aquires the lock.
*/
DECLINLINE(void) rtmemBlockLock(void)
{
unsigned c = 0;
}
/**
* Releases the lock.
*/
DECLINLINE(void) rtmemBlockUnlock(void)
{
ASMAtomicXchgU32(&g_BlocksLock, 0);
}
/**
* Creates a block.
*/
{
if (pBlock)
{
}
return pBlock;
}
/**
* Frees a block.
*/
{
}
/**
* Insert a block from the tree.
*/
{
}
/**
* Remove a block from the tree and returns it to the caller.
*/
{
return pBlock;
}
/**
* Gets a block.
*/
{
return pBlock;
}
/**
* Dumps one allocation.
*/
{
(unsigned long)pBlock->cbUnaligned,
return 0;
}
/**
* Dumps the allocated blocks.
* This is something which you should call from gdb.
*/
extern "C" void RTMemDump(void);
void RTMemDump(void)
{
}
#ifdef RTALLOC_EFENCE_FREE_DELAYED
/**
* Insert a delayed block.
*/
{
if (g_pBlocksDelayHead)
{
}
else
{
}
}
/**
* Removes a delayed block.
*/
{
{
if (pBlock)
{
else
}
}
return pBlock;
}
#endif /* DELAY */
#endif /* RTALLOC_EFENCE_TRACE */
/**
* Internal allocator.
*/
RTDECL(void *) rtR3MemAlloc(const char *pszOp, RTMEMTYPE enmType, size_t cbUnaligned, size_t cbAligned,
{
/*
* Sanity.
*/
&& RTALLOC_EFENCE_SIZE <= 0)
{
return NULL;
}
if (!cbUnaligned)
{
#if 0
return NULL;
#else
#endif
}
#ifndef RTALLOC_EFENCE_IN_FRONT
/* Alignment decreases fence accuracy, but this is at least partially
* counteracted by filling and checking the alignment padding. When the
* fence is in front then then no extra alignment is needed. */
#endif
#ifdef RTALLOC_EFENCE_TRACE
/*
* Allocate the trace block.
*/
PRTMEMBLOCK pBlock = rtmemBlockCreate(enmType, cbUnaligned, cbAligned, pszTag, pvCaller, RT_SRC_POS_ARGS);
if (!pBlock)
{
return NULL;
}
#endif
/*
* Allocate a block with page alignment space + the size of the E-fence.
*/
if (pvBlock)
{
/*
* Calc the start of the fence and the user block
* and then change the page protection of the fence.
*/
#ifdef RTALLOC_EFENCE_IN_FRONT
# ifdef RTALLOC_EFENCE_NOMAN_FILLER
memset((char *)pv + cbUnaligned, RTALLOC_EFENCE_NOMAN_FILLER, cbBlock - RTALLOC_EFENCE_SIZE - cbUnaligned);
# endif
#else
# ifdef RTALLOC_EFENCE_NOMAN_FILLER
# endif
#endif
#ifdef RTALLOC_EFENCE_FENCE_FILLER
#endif
if (!rc)
{
#ifdef RTALLOC_EFENCE_TRACE
#endif
if (enmType == RTMEMTYPE_RTMEMALLOCZ)
#ifdef RTALLOC_EFENCE_FILLER
else
#endif
rtmemLog(pszOp, "returns %p (pvBlock=%p cbBlock=%#x pvEFence=%p cbUnaligned=%#x)\n", pv, pvBlock, cbBlock, pvEFence, cbUnaligned);
return pv;
}
rtmemComplain(pszOp, "RTMemProtect failed, pvEFence=%p size %d, rc=%d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
}
else
rtmemComplain(pszOp, "Failed to allocated %lu (%lu) bytes.\n", (unsigned long)cbBlock, (unsigned long)cbUnaligned);
#ifdef RTALLOC_EFENCE_TRACE
#endif
return NULL;
}
/**
* Internal free.
*/
RTDECL(void) rtR3MemFree(const char *pszOp, RTMEMTYPE enmType, void *pv, void *pvCaller, RT_SRC_POS_DECL)
{
/*
* Simple case.
*/
if (!pv)
return;
/*
* Check watch points.
*/
for (unsigned i = 0; i < RT_ELEMENTS(gapvRTMemFreeWatch); i++)
if (gapvRTMemFreeWatch[i] == pv)
#ifdef RTALLOC_EFENCE_TRACE
/*
* Find the block.
*/
if (pBlock)
{
if (gfRTMemFreeLog)
RTLogPrintf("RTMem %s: pv=%p pvCaller=%p cbUnaligned=%#x\n", pszOp, pv, pvCaller, pBlock->cbUnaligned);
# ifdef RTALLOC_EFENCE_NOMAN_FILLER
/*
* Check whether the no man's land is untouched.
*/
# ifdef RTALLOC_EFENCE_IN_FRONT
# else
/* Alignment must match allocation alignment in rtMemAlloc(). */
if (pvWrong)
# endif
if (pvWrong)
# endif
# ifdef RTALLOC_EFENCE_FREE_FILL
/*
* Fill the user part of the block.
*/
# endif
# if defined(RTALLOC_EFENCE_FREE_DELAYED) && RTALLOC_EFENCE_FREE_DELAYED > 0
/*
* We're doing delayed freeing.
* That means we'll expand the E-fence to cover the entire block.
*/
if (RT_SUCCESS(rc))
{
/*
* Insert it into the free list and process pending frees.
*/
{
# ifdef RTALLOC_EFENCE_IN_FRONT
# else
# endif
if (RT_SUCCESS(rc))
else
rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvBlock, cbBlock, rc);
}
}
else
# else /* !RTALLOC_EFENCE_FREE_DELAYED */
/*
* Turn of the E-fence and free it.
*/
# ifdef RTALLOC_EFENCE_IN_FRONT
# else
# endif
if (RT_SUCCESS(rc))
else
rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
# endif /* !RTALLOC_EFENCE_FREE_DELAYED */
}
else
#else /* !RTALLOC_EFENCE_TRACE */
/*
* We have no size tracking, so we're not doing any freeing because
* we cannot if the E-fence is after the block.
* Let's just expand the E-fence to the first page of the user bit
* since we know that it's around.
*/
if (RT_FAILURE(rc))
rtmemComplain(pszOp, "RTMemProtect(%p, PAGE_SIZE, RTMEM_PROT_NONE) -> %d\n", (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), rc);
#endif /* !RTALLOC_EFENCE_TRACE */
}
/**
* Internal realloc.
*/
{
/*
* Allocate new and copy.
*/
if (!pvOld)
if (!cbNew)
{
return NULL;
}
#ifdef RTALLOC_EFENCE_TRACE
/*
* Get the block, allocate the new, copy the data, free the old one.
*/
if (pBlock)
{
if (pvRet)
{
}
return pvRet;
}
else
return NULL;
#else /* !RTALLOC_EFENCE_TRACE */
return NULL;
#endif /* !RTALLOC_EFENCE_TRACE */
}
{
return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
{
return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
{
if (pv)
}
{
return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
{
return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
{
if (cbUnaligned >= 16)
else
return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
RTDECL(void *) RTMemEfAllocZVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW
{
if (cbUnaligned >= 16)
else
return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
RTDECL(void *) RTMemEfRealloc(void *pvOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW
{
return rtR3MemRealloc("Realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
}
{
if (pv)
}
RTDECL(void *) RTMemEfDup(const void *pvSrc, size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW
{
if (pvDst)
return pvDst;
}
RTDECL(void *) RTMemEfDupEx(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW
{
if (pvDst)
{
}
return pvDst;
}
/*
*
* The NP (no position) versions.
*
*/
{
return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
return rtR3MemAlloc("TmpAllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
if (pv)
}
{
return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
if (cbUnaligned >= 16)
else
return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
if (cbUnaligned >= 16)
else
return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
return rtR3MemRealloc("Realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), NULL, 0, NULL);
}
{
if (pv)
}
{
if (pvDst)
return pvDst;
}
RTDECL(void *) RTMemEfDupExNP(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW
{
if (pvDst)
{
}
return pvDst;
}