VirtualBox

Changeset 53278 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Nov 9, 2014 9:01:25 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
96850
Message:

IPRT: Added experimental malloc replacement feature, add RTALLOC_REPLACE_MALLOC and VBOX_WITH_EF_WRAPS to LocalConfig.kmk (only tested on 64-bit darwin).

Location:
trunk/src/VBox/Runtime/r3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/alloc-ef.cpp

    r52333 r53278  
    4545#include <iprt/string.h>
    4646
     47#ifdef RTALLOC_REPLACE_MALLOC
     48# include <VBox/dis.h>
     49# include <VBox/disopcode.h>
     50# include <dlfcn.h>
     51# ifdef RT_OS_DARWIN
     52#  include <malloc/malloc.h>
     53# endif
     54#endif
     55
     56
     57/*******************************************************************************
     58*   Defined Constants And Macros                                               *
     59*******************************************************************************/
     60#ifdef RTALLOC_REPLACE_MALLOC
     61# define RTMEM_REPLACMENT_ALIGN(a_cb) ((a_cb) >= 16 ? RT_ALIGN_Z(a_cb, 16) \
     62                                       : (a_cb) >= sizeof(uintptr_t) ? RT_ALIGN_Z(a_cb,  sizeof(uintptr_t)) : (a_cb))
     63#endif
     64
    4765
    4866/*******************************************************************************
     
    6280static volatile size_t      g_cbBlocksDelay;
    6381# endif /* RTALLOC_EFENCE_FREE_DELAYED */
     82# ifdef RTALLOC_REPLACE_MALLOC
     83/** @name For calling the real allocation API we've replaced.
     84 * @{ */
     85void * (*g_pfnOrgMalloc)(size_t);
     86void * (*g_pfnOrgCalloc)(size_t, size_t);
     87void * (*g_pfnOrgRealloc)(void *, size_t);
     88void   (*g_pfnOrgFree)(void *);
     89size_t (*g_pfnOrgMallocSize)(void *);
     90/** @} */
     91# endif
    6492#endif /* RTALLOC_EFENCE_TRACE */
    6593/** Array of pointers free watches for. */
     
    72100*   Internal Functions                                                         *
    73101*******************************************************************************/
     102#ifdef RTALLOC_REPLACE_MALLOC
     103static void rtMemReplaceMallocAndFriends(void);
     104#endif
     105
     106
    74107/**
    75108 * Complains about something.
     
    131164                                         const char *pszTag, void *pvCaller, RT_SRC_POS_DECL)
    132165{
     166# ifdef RTALLOC_REPLACE_MALLOC
     167    if (!g_pfnOrgMalloc)
     168        rtMemReplaceMallocAndFriends();
     169    PRTMEMBLOCK pBlock = (PRTMEMBLOCK)g_pfnOrgMalloc(sizeof(*pBlock));
     170# else
    133171    PRTMEMBLOCK pBlock = (PRTMEMBLOCK)malloc(sizeof(*pBlock));
     172# endif
    134173    if (pBlock)
    135174    {
     
    152191DECLINLINE(void) rtmemBlockFree(PRTMEMBLOCK pBlock)
    153192{
     193# ifdef RTALLOC_REPLACE_MALLOC
     194    g_pfnOrgFree(pBlock);
     195# else
    154196    free(pBlock);
     197# endif
    155198}
    156199
     
    270313
    271314#endif /* RTALLOC_EFENCE_TRACE */
     315
     316
     317#if defined(RTALLOC_REPLACE_MALLOC) && defined(RTALLOC_EFENCE_TRACE)
     318/*
     319 *
     320 * Replacing malloc, calloc, realloc, & free.
     321 *
     322 */
     323
     324/** Replacement for malloc. */
     325static void *rtMemReplacementMalloc(size_t cb)
     326{
     327    size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cb);
     328    void *pv = rtR3MemAlloc("r-malloc", RTMEMTYPE_RTMEMALLOC, cb, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
     329    if (!pv)
     330        pv = g_pfnOrgMalloc(cb);
     331    return pv;
     332}
     333
     334/** Replacement for calloc. */
     335static void *rtMemReplacementCalloc(size_t cbItem, size_t cItems)
     336{
     337    size_t cb = cbItem * cItems;
     338    size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cb);
     339    void *pv = rtR3MemAlloc("r-calloc", RTMEMTYPE_RTMEMALLOCZ, cb, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
     340    if (!pv)
     341        pv = g_pfnOrgCalloc(cbItem, cItems);
     342    return pv;
     343}
     344
     345/** Replacement for realloc. */
     346static void *rtMemReplacementRealloc(void *pvOld, size_t cbNew)
     347{
     348    if (pvOld)
     349    {
     350        /* We're not strict about where the memory was allocated. */
     351        PRTMEMBLOCK pBlock = rtmemBlockGet(pvOld);
     352        if (pBlock)
     353        {
     354            size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cbNew);
     355            return rtR3MemRealloc("r-realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
     356        }
     357        return g_pfnOrgRealloc(pvOld, cbNew);
     358    }
     359    return rtMemReplacementMalloc(cbNew);
     360}
     361
     362/** Replacement for free(). */
     363static void rtMemReplacementFree(void *pv)
     364{
     365    if (pv)
     366    {
     367        /* We're not strict about where the memory was allocated. */
     368        PRTMEMBLOCK pBlock = rtmemBlockGet(pv);
     369        if (pBlock)
     370            rtR3MemFree("r-free", RTMEMTYPE_RTMEMFREE, pv, ASMReturnAddress(), RT_SRC_POS);
     371        else
     372            g_pfnOrgFree(pv);
     373    }
     374}
     375
     376# ifdef RT_OS_DARWIN
     377/** Replacement for malloc. */
     378static size_t rtMemReplacementMallocSize(void *pv)
     379{
     380    size_t cb;
     381    if (pv)
     382    {
     383        /* We're not strict about where the memory was allocated. */
     384        PRTMEMBLOCK pBlock = rtmemBlockGet(pv);
     385        if (pBlock)
     386            cb = pBlock->cbUnaligned;
     387        else
     388            cb = g_pfnOrgMallocSize(pv);
     389    }
     390    else
     391        cb = 0;
     392    return cb;
     393}
     394# endif
     395
     396
     397static void rtMemReplaceMallocAndFriends(void)
     398{
     399    struct
     400    {
     401        const char *pszName;
     402        PFNRT       pfnReplacement;
     403        PFNRT       pfnOrg;
     404        PFNRT      *ppfnJumpBack;
     405    } aApis[] =
     406    {
     407        { "free",    (PFNRT)rtMemReplacementFree,    (PFNRT)free,    (PFNRT *)&g_pfnOrgFree },
     408        { "realloc", (PFNRT)rtMemReplacementRealloc, (PFNRT)realloc, (PFNRT *)&g_pfnOrgRealloc },
     409        { "calloc",  (PFNRT)rtMemReplacementCalloc,  (PFNRT)calloc,  (PFNRT *)&g_pfnOrgCalloc },
     410        { "malloc",  (PFNRT)rtMemReplacementMalloc,  (PFNRT)malloc,  (PFNRT *)&g_pfnOrgMalloc },
     411#ifdef RT_OS_DARWIN
     412        { "malloc_size", (PFNRT)rtMemReplacementMallocSize,  (PFNRT)malloc_size,  (PFNRT *)&g_pfnOrgMallocSize },
     413#endif
     414    };
     415
     416    /*
     417     * Initialize the jump backs to avoid recursivly entering this function.
     418     */
     419    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
     420        *aApis[i].ppfnJumpBack = aApis[i].pfnOrg;
     421
     422    /*
     423     * Give the user an option to skip replacing malloc.
     424     */
     425    if (getenv("IPRT_DONT_REPLACE_MALLOC"))
     426        return;
     427
     428    /*
     429     * Allocate a page for jump back code (we leak it).
     430     */
     431    uint8_t *pbExecPage = (uint8_t *)RTMemPageAlloc(PAGE_SIZE); AssertFatal(pbExecPage);
     432    int rc = RTMemProtect(pbExecPage, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);
     433
     434    /*
     435     * Do the ground work.
     436     */
     437    uint8_t *pb = pbExecPage;
     438    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
     439    {
     440        /* Resolve it. */
     441        PFNRT pfnOrg = (PFNRT)(uintptr_t)dlsym(RTLD_DEFAULT, aApis[i].pszName);
     442        if (pfnOrg)
     443            aApis[i].pfnOrg = pfnOrg;
     444        else
     445            pfnOrg = aApis[i].pfnOrg;
     446
     447        /* Figure what we can replace and how much to duplicate in the jump back code. */
     448# ifdef RT_ARCH_AMD64
     449        uint32_t         cbNeeded   = 12;
     450        DISCPUMODE const enmCpuMode = DISCPUMODE_64BIT;
     451# elif defined(RT_ARCH_X86)
     452        uint32_t   const cbNeeded   = 5;
     453        DISCPUMODE const enmCpuMode = DISCPUMODE_32BIT;
     454# else
     455#  error "Port me"
     456# endif
     457        uint32_t offJmpBack = 0;
     458        uint32_t cbCopy = 0;
     459        while (offJmpBack < cbNeeded)
     460        {
     461            DISCPUSTATE Dis;
     462            uint32_t cbInstr = 1;
     463            rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
     464            AssertFatal(!(Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)));
     465# ifdef RT_ARCH_AMD64
     466#  ifdef RT_OS_DARWIN
     467            /* Kludge for: cmp [malloc_def_zone_state], 1; jg 2; call _malloc_initialize; 2: */
     468            DISQPVPARAMVAL Parm;
     469            if (   Dis.ModRM.Bits.Mod == 0
     470                && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */
     471                && (Dis.Param2.fUse & (DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
     472                && Dis.Param2.uValue == 1
     473                && Dis.pCurInstr->uOpcode == OP_CMP)
     474            {
     475                cbCopy = offJmpBack;
     476
     477                offJmpBack += cbInstr;
     478                rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
     479                if (   Dis.pCurInstr->uOpcode == OP_JNBE
     480                    && Dis.Param1.uDisp.i8 == 5)
     481                {
     482                    offJmpBack += cbInstr + 5;
     483                    AssertFatal(offJmpBack >= cbNeeded);
     484                    break;
     485                }
     486            }
     487#  endif
     488            AssertFatal(!(Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */));
     489# endif
     490            offJmpBack += cbInstr;
     491        }
     492        if (!cbCopy)
     493            cbCopy = offJmpBack;
     494
     495        /* Assemble the jump back. */
     496        memcpy(pb, (void *)(uintptr_t)pfnOrg, cbCopy);
     497        uint32_t off = cbCopy;
     498# ifdef RT_ARCH_AMD64
     499        pb[off++] = 0xff; /* jmp qword [$+8 wrt RIP] */
     500        pb[off++] = 0x25;
     501        *(uint32_t *)&pb[off] = 0;
     502        off += 4;
     503        *(uint64_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack;
     504        off += 8;
     505        off = RT_ALIGN_32(off, 16);
     506# elif defined(RT_ARCH_X86)
     507        pb[off++] = 0xe9; /* jmp rel32 */
     508        *(uint32_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack - (uintptr_t)&pb[4];
     509        off += 4;
     510        off = RT_ALIGN_32(off, 8);
     511# else
     512#  error "Port me"
     513# endif
     514        *aApis[i].ppfnJumpBack = (PFNRT)(uintptr_t)pb;
     515        pb += off;
     516    }
     517
     518    /*
     519     * Modify the APIs.
     520     */
     521    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
     522    {
     523        pb = (uint8_t *)(uintptr_t)aApis[i].pfnOrg;
     524        rc = RTMemProtect(pb, 16, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);
     525
     526# ifdef RT_ARCH_AMD64
     527        /* Assemble the LdrLoadDll patch. */
     528        *pb++ = 0x48; /* mov rax, qword */
     529        *pb++ = 0xb8;
     530        *(uint64_t *)pb = (uintptr_t)aApis[i].pfnReplacement;
     531        pb += 8;
     532        *pb++ = 0xff; /* jmp rax */
     533        *pb++ = 0xe0;
     534# elif defined(RT_ARCH_X86)
     535        *pb++ = 0xe9; /* jmp rel32 */
     536        *(uint32_t *)pb = (uintptr_t)aApis[i].pfnReplacement - (uintptr_t)&pb[4];
     537# else
     538#  error "Port me"
     539# endif
     540    }
     541}
     542
     543#endif /* RTALLOC_REPLACE_MALLOC && RTALLOC_EFENCE_TRACE */
    272544
    273545
  • trunk/src/VBox/Runtime/r3/alloc-ef.h

    r34291 r53278  
    119119#endif
    120120
     121#if defined(RUNNING_DOXYGEN)
     122/** @def RTALLOC_REPLACE_MALLOC
     123 * Replaces the malloc, calloc, realloc, free and friends in libc (experimental).
     124 * Set in LocalConfig.kmk. Requires RTALLOC_EFENCE_TRACE to work. */
     125# define RTALLOC_REPLACE_MALLOC
     126#endif
     127#if defined(RTALLOC_REPLACE_MALLOC) && !defined(RTALLOC_EFENCE_TRACE)
     128# error "RTALLOC_REPLACE_MALLOC requires RTALLOC_EFENCE_TRACE."
     129#endif
    121130
    122131
     
    192201RT_C_DECLS_END
    193202
    194 #endif
    195 
     203
     204/*******************************************************************************
     205*   Global Variables                                                           *
     206*******************************************************************************/
     207#ifdef RTALLOC_REPLACE_MALLOC
     208RT_C_DECLS_BEGIN
     209extern void * (*g_pfnOrgMalloc)(size_t);
     210extern void * (*g_pfnOrgCalloc)(size_t, size_t);
     211extern void * (*g_pfnOrgRealloc)(void *, size_t);
     212extern void   (*g_pfnOrgFree)(void *);
     213RT_C_DECLS_END
     214#endif
     215
     216#endif
     217
  • trunk/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp

    r48935 r53278  
    4141#include <iprt/string.h>
    4242#include "internal/mem.h"
     43#include "../alloc-ef.h"
    4344
    4445#include <stdlib.h>
     
    412413    }
    413414    /** @todo Eliminate this rtMemBaseAlloc dependency! */
    414     PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)rtMemBaseAlloc(sizeof(*pBlock));
     415    PRTHEAPPAGEBLOCK pBlock;
     416#ifdef RTALLOC_REPLACE_MALLOC
     417    if (g_pfnOrgMalloc)
     418        pBlock = (PRTHEAPPAGEBLOCK)g_pfnOrgMalloc(sizeof(*pBlock));
     419    else
     420#endif
     421        pBlock = (PRTHEAPPAGEBLOCK)rtMemBaseAlloc(sizeof(*pBlock));
    415422    if (!pBlock)
    416423    {
     
    583590                        pBlock->Core.Key = pBlock->Core.KeyLast = NULL;
    584591                        pBlock->cFreePages = 0;
    585                         rtMemBaseFree(pBlock);
     592#ifdef RTALLOC_REPLACE_MALLOC
     593                        if (g_pfnOrgFree)
     594                            g_pfnOrgFree(pBlock);
     595                        else
     596#endif
     597                            rtMemBaseFree(pBlock);
    586598
    587599                        RTCritSectEnter(&pHeap->CritSect);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette