/* $Id: asn1-efence-allocator.cpp $ */ /** @file * IPRT - ASN.1, Electric Fense Allocator. */ /* * Copyright (C) 2006-2019 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * 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 "internal/iprt.h" #include #include #include #include /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnFree} */ static DECLCALLBACK(void) rtAsn1EFenceAllocator_Free(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation, void *pv) { RT_NOREF_PV(pThis); RTMemEfFreeNP(pv); pAllocation->cbAllocated = 0; } /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnAlloc} */ static DECLCALLBACK(int) rtAsn1EFenceAllocator_Alloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation, void **ppv, size_t cb) { void *pv = RTMemEfAllocZNP(cb, RTMEM_TAG); if (pv) { *ppv = pv; pAllocation->cbAllocated = (uint32_t)cb; return VINF_SUCCESS; } RT_NOREF_PV(pThis); return VERR_NO_MEMORY; } /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnRealloc} */ static DECLCALLBACK(int) rtAsn1EFenceAllocator_Realloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation, void *pvOld, void **ppvNew, size_t cbNew) { Assert(pvOld); Assert(cbNew); void *pv = RTMemEfReallocNP(pvOld, cbNew, RTMEM_TAG); if (pv) { *ppvNew = pv; pAllocation->cbAllocated = (uint32_t)cbNew; return VINF_SUCCESS; } RT_NOREF_PV(pThis); return VERR_NO_MEMORY; } /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnFreeArray} */ static DECLCALLBACK(void) rtAsn1EFenceAllocator_FreeArray(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ARRAYALLOCATION pAllocation, void **papvArray) { RT_NOREF_PV(pThis); Assert(papvArray); Assert(pAllocation->cbEntry); Assert(pAllocation->cEntriesAllocated <= pAllocation->cPointersAllocated); uint32_t i = pAllocation->cEntriesAllocated; while (i-- > 0) { RTMemEfFreeNP(papvArray[i]); papvArray[i] = NULL; } RTMemEfFreeNP(papvArray); pAllocation->cEntriesAllocated = 0; pAllocation->cPointersAllocated = 0; } /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnGrowArray} */ static DECLCALLBACK(int) rtAsn1EFenceAllocator_GrowArray(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ARRAYALLOCATION pAllocation, void ***ppapvArray, uint32_t cMinEntries) { RT_NOREF_PV(pThis); Assert(pAllocation->cbEntry); Assert(pAllocation->cEntriesAllocated <= pAllocation->cPointersAllocated); /* * Resize the pointer array. */ void **papvArray = *ppapvArray; void *pvPointers = RTMemEfReallocNP(papvArray, cMinEntries * sizeof(void *), RTMEM_TAG); if (pvPointers) { *ppapvArray = papvArray = (void **)pvPointers; if (cMinEntries > pAllocation->cPointersAllocated) /* possible on multiple shrink failures */ RT_BZERO(&papvArray[pAllocation->cPointersAllocated], (cMinEntries - pAllocation->cPointersAllocated) * sizeof(void *)); else AssertFailed(); pAllocation->cPointersAllocated = cMinEntries; } else if (cMinEntries > pAllocation->cPointersAllocated) return VERR_NO_MEMORY; /* else: possible but unlikely */ /* * Add more entries. */ while (pAllocation->cEntriesAllocated < cMinEntries) { void *pv; papvArray[pAllocation->cEntriesAllocated] = pv = RTMemEfAllocZNP(pAllocation->cbEntry, RTMEM_TAG); if (pv) pAllocation->cEntriesAllocated++; else return VERR_NO_MEMORY; } return VINF_SUCCESS; } /** @interface_method_impl{RTASN1ALLOCATORVTABLE,pfnShrinkArray} */ static DECLCALLBACK(void) rtAsn1EFenceAllocator_ShrinkArray(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ARRAYALLOCATION pAllocation, void ***ppapvArray, uint32_t cNew, uint32_t cCurrent) { RT_NOREF_PV(pThis); Assert(pAllocation->cbEntry); Assert(pAllocation->cEntriesAllocated <= pAllocation->cPointersAllocated); /* * We always free and resize. */ Assert(pAllocation->cEntriesAllocated == cCurrent); Assert(cNew < cCurrent); /* Free entries. */ void **papvArray = *ppapvArray; while (cCurrent-- > cNew) { RTMemEfFreeNP(papvArray[cCurrent]); papvArray[cCurrent] = NULL; } pAllocation->cEntriesAllocated = cNew; /* Try resize pointer array. Failure here is a genuine possibility since the efence code will try allocate a new block. This causes extra fun in the grow method above. */ void *pvPointers = RTMemEfReallocNP(papvArray, cNew * sizeof(void *), RTMEM_TAG); if (pvPointers) { *ppapvArray = (void **)pvPointers; pAllocation->cPointersAllocated = cNew; } } /** The Electric Fence ASN.1 allocator. */ RT_DECL_DATA_CONST(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator = { rtAsn1EFenceAllocator_Free, rtAsn1EFenceAllocator_Alloc, rtAsn1EFenceAllocator_Realloc, rtAsn1EFenceAllocator_FreeArray, rtAsn1EFenceAllocator_GrowArray, rtAsn1EFenceAllocator_ShrinkArray }; #if 0 && defined(IN_RING3) /* for efence testing */ RT_DECL_DATA_CONST(RTASN1ALLOCATORVTABLE const) g_RTAsn1DefaultAllocator = { rtAsn1EFenceAllocator_Free, rtAsn1EFenceAllocator_Alloc, rtAsn1EFenceAllocator_Realloc, rtAsn1EFenceAllocator_FreeArray, rtAsn1EFenceAllocator_GrowArray, rtAsn1EFenceAllocator_ShrinkArray }; #endif