VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/alloc-ef.cpp@ 96407

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 33.7 KB
Line 
1/* $Id: alloc-ef.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, electric fence.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "alloc-ef.h"
42#include <iprt/mem.h>
43#include <iprt/log.h>
44#include <iprt/asm.h>
45#include <iprt/thread.h>
46#include <VBox/sup.h>
47#include <iprt/errcore.h>
48#ifndef IPRT_NO_CRT
49# include <errno.h>
50# include <stdio.h>
51# include <stdlib.h>
52#endif
53
54#include <iprt/alloc.h>
55#include <iprt/assert.h>
56#include <iprt/param.h>
57#include <iprt/string.h>
58
59#ifdef RTALLOC_REPLACE_MALLOC
60# include <VBox/dis.h>
61# include <VBox/disopcode.h>
62# include <dlfcn.h>
63# ifdef RT_OS_DARWIN
64# include <malloc/malloc.h>
65# endif
66#endif
67
68
69/*********************************************************************************************************************************
70* Defined Constants And Macros *
71*********************************************************************************************************************************/
72#ifdef RTALLOC_REPLACE_MALLOC
73# define RTMEM_REPLACMENT_ALIGN(a_cb) ((a_cb) >= 16 ? RT_ALIGN_Z(a_cb, 16) \
74 : (a_cb) >= sizeof(uintptr_t) ? RT_ALIGN_Z(a_cb, sizeof(uintptr_t)) : (a_cb))
75#endif
76
77
78/*********************************************************************************************************************************
79* Global Variables *
80*********************************************************************************************************************************/
81#ifdef RTALLOC_EFENCE_TRACE
82/** Spinlock protecting the all the block's globals. */
83static volatile uint32_t g_BlocksLock;
84/** Tree tracking the allocations. */
85static AVLPVTREE g_BlocksTree;
86# ifdef RTALLOC_EFENCE_FREE_DELAYED
87/** Tail of the delayed blocks. */
88static volatile PRTMEMBLOCK g_pBlocksDelayHead;
89/** Tail of the delayed blocks. */
90static volatile PRTMEMBLOCK g_pBlocksDelayTail;
91/** Number of bytes in the delay list (includes fences). */
92static volatile size_t g_cbBlocksDelay;
93# endif /* RTALLOC_EFENCE_FREE_DELAYED */
94# ifdef RTALLOC_REPLACE_MALLOC
95/** @name For calling the real allocation API we've replaced.
96 * @{ */
97void * (*g_pfnOrgMalloc)(size_t);
98void * (*g_pfnOrgCalloc)(size_t, size_t);
99void * (*g_pfnOrgRealloc)(void *, size_t);
100void (*g_pfnOrgFree)(void *);
101size_t (*g_pfnOrgMallocSize)(void *);
102/** @} */
103# endif
104#endif /* RTALLOC_EFENCE_TRACE */
105/** Array of pointers free watches for. */
106void *gapvRTMemFreeWatch[4] = {NULL, NULL, NULL, NULL};
107/** Enable logging of all freed memory. */
108bool gfRTMemFreeLog = false;
109
110
111/*********************************************************************************************************************************
112* Internal Functions *
113*********************************************************************************************************************************/
114#ifdef RTALLOC_REPLACE_MALLOC
115static void rtMemReplaceMallocAndFriends(void);
116#endif
117
118
119/**
120 * Complains about something.
121 */
122static void rtmemComplain(const char *pszOp, const char *pszFormat, ...)
123{
124 va_list args;
125 fprintf(stderr, "RTMem error: %s: ", pszOp);
126 va_start(args, pszFormat);
127 vfprintf(stderr, pszFormat, args);
128 va_end(args);
129 RTAssertDoPanic();
130}
131
132/**
133 * Log an event.
134 */
135DECLINLINE(void) rtmemLog(const char *pszOp, const char *pszFormat, ...)
136{
137#if 0
138 va_list args;
139 fprintf(stderr, "RTMem info: %s: ", pszOp);
140 va_start(args, pszFormat);
141 vfprintf(stderr, pszFormat, args);
142 va_end(args);
143#else
144 NOREF(pszOp); NOREF(pszFormat);
145#endif
146}
147
148
149#ifdef RTALLOC_EFENCE_TRACE
150
151/**
152 * Acquires the lock.
153 */
154DECLINLINE(void) rtmemBlockLock(void)
155{
156 unsigned c = 0;
157 while (!ASMAtomicCmpXchgU32(&g_BlocksLock, 1, 0))
158 RTThreadSleepNoLog(((++c) >> 2) & 31);
159}
160
161
162/**
163 * Releases the lock.
164 */
165DECLINLINE(void) rtmemBlockUnlock(void)
166{
167 Assert(g_BlocksLock == 1);
168 ASMAtomicXchgU32(&g_BlocksLock, 0);
169}
170
171
172/**
173 * Creates a block.
174 */
175DECLINLINE(PRTMEMBLOCK) rtmemBlockCreate(RTMEMTYPE enmType, size_t cbUnaligned, size_t cbAligned,
176 const char *pszTag, void *pvCaller, RT_SRC_POS_DECL)
177{
178# ifdef RTALLOC_REPLACE_MALLOC
179 if (!g_pfnOrgMalloc)
180 rtMemReplaceMallocAndFriends();
181 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)g_pfnOrgMalloc(sizeof(*pBlock));
182# else
183 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)malloc(sizeof(*pBlock));
184# endif
185 if (pBlock)
186 {
187 pBlock->enmType = enmType;
188 pBlock->cbUnaligned = cbUnaligned;
189 pBlock->cbAligned = cbAligned;
190 pBlock->pszTag = pszTag;
191 pBlock->pvCaller = pvCaller;
192 pBlock->iLine = iLine;
193 pBlock->pszFile = pszFile;
194 pBlock->pszFunction = pszFunction;
195 }
196 return pBlock;
197}
198
199
200/**
201 * Frees a block.
202 */
203DECLINLINE(void) rtmemBlockFree(PRTMEMBLOCK pBlock)
204{
205# ifdef RTALLOC_REPLACE_MALLOC
206 g_pfnOrgFree(pBlock);
207# else
208 free(pBlock);
209# endif
210}
211
212
213/**
214 * Insert a block from the tree.
215 */
216DECLINLINE(void) rtmemBlockInsert(PRTMEMBLOCK pBlock, void *pv)
217{
218 pBlock->Core.Key = pv;
219 rtmemBlockLock();
220 bool fRc = RTAvlPVInsert(&g_BlocksTree, &pBlock->Core);
221 rtmemBlockUnlock();
222 AssertRelease(fRc);
223}
224
225
226/**
227 * Remove a block from the tree and returns it to the caller.
228 */
229DECLINLINE(PRTMEMBLOCK) rtmemBlockRemove(void *pv)
230{
231 rtmemBlockLock();
232 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)RTAvlPVRemove(&g_BlocksTree, pv);
233 rtmemBlockUnlock();
234 return pBlock;
235}
236
237/**
238 * Gets a block.
239 */
240DECLINLINE(PRTMEMBLOCK) rtmemBlockGet(void *pv)
241{
242 rtmemBlockLock();
243 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)RTAvlPVGet(&g_BlocksTree, pv);
244 rtmemBlockUnlock();
245 return pBlock;
246}
247
248/**
249 * Dumps one allocation.
250 */
251static DECLCALLBACK(int) RTMemDumpOne(PAVLPVNODECORE pNode, void *pvUser)
252{
253 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)pNode;
254 fprintf(stderr, "%p %08lx(+%02lx) %p\n",
255 pBlock->Core.Key,
256 (unsigned long)pBlock->cbUnaligned,
257 (unsigned long)(pBlock->cbAligned - pBlock->cbUnaligned),
258 pBlock->pvCaller);
259 NOREF(pvUser);
260 return 0;
261}
262
263/**
264 * Dumps the allocated blocks.
265 * This is something which you should call from gdb.
266 */
267extern "C" void RTMemDump(void);
268void RTMemDump(void)
269{
270 fprintf(stderr, "address size(alg) caller\n");
271 RTAvlPVDoWithAll(&g_BlocksTree, true, RTMemDumpOne, NULL);
272}
273
274# ifdef RTALLOC_EFENCE_FREE_DELAYED
275
276/**
277 * Insert a delayed block.
278 */
279DECLINLINE(void) rtmemBlockDelayInsert(PRTMEMBLOCK pBlock)
280{
281 size_t cbBlock = RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
282 pBlock->Core.pRight = NULL;
283 pBlock->Core.pLeft = NULL;
284 rtmemBlockLock();
285 if (g_pBlocksDelayHead)
286 {
287 g_pBlocksDelayHead->Core.pLeft = (PAVLPVNODECORE)pBlock;
288 pBlock->Core.pRight = (PAVLPVNODECORE)g_pBlocksDelayHead;
289 g_pBlocksDelayHead = pBlock;
290 }
291 else
292 {
293 g_pBlocksDelayTail = pBlock;
294 g_pBlocksDelayHead = pBlock;
295 }
296 g_cbBlocksDelay += cbBlock;
297 rtmemBlockUnlock();
298}
299
300/**
301 * Removes a delayed block.
302 */
303DECLINLINE(PRTMEMBLOCK) rtmemBlockDelayRemove(void)
304{
305 PRTMEMBLOCK pBlock = NULL;
306 rtmemBlockLock();
307 if (g_cbBlocksDelay > RTALLOC_EFENCE_FREE_DELAYED)
308 {
309 pBlock = g_pBlocksDelayTail;
310 if (pBlock)
311 {
312 g_pBlocksDelayTail = (PRTMEMBLOCK)pBlock->Core.pLeft;
313 if (pBlock->Core.pLeft)
314 pBlock->Core.pLeft->pRight = NULL;
315 else
316 g_pBlocksDelayHead = NULL;
317 g_cbBlocksDelay -= RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
318 }
319 }
320 rtmemBlockUnlock();
321 return pBlock;
322}
323
324
325/**
326 * Dumps the freed blocks.
327 * This is something which you should call from gdb.
328 */
329extern "C" void RTMemDumpFreed(void);
330void RTMemDumpFreed(void)
331{
332 fprintf(stderr, "address size(alg) caller\n");
333 for (PRTMEMBLOCK pCur = g_pBlocksDelayHead; pCur; pCur = (PRTMEMBLOCK)pCur->Core.pRight)
334 RTMemDumpOne(&pCur->Core, NULL);
335
336}
337
338# endif /* RTALLOC_EFENCE_FREE_DELAYED */
339
340#endif /* RTALLOC_EFENCE_TRACE */
341
342
343#if defined(RTALLOC_REPLACE_MALLOC) && defined(RTALLOC_EFENCE_TRACE)
344/*
345 *
346 * Replacing malloc, calloc, realloc, & free.
347 *
348 */
349
350/** Replacement for malloc. */
351static void *rtMemReplacementMalloc(size_t cb)
352{
353 size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cb);
354 void *pv = rtR3MemAlloc("r-malloc", RTMEMTYPE_RTMEMALLOC, cb, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
355 if (!pv)
356 pv = g_pfnOrgMalloc(cb);
357 return pv;
358}
359
360/** Replacement for calloc. */
361static void *rtMemReplacementCalloc(size_t cbItem, size_t cItems)
362{
363 size_t cb = cbItem * cItems;
364 size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cb);
365 void *pv = rtR3MemAlloc("r-calloc", RTMEMTYPE_RTMEMALLOCZ, cb, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
366 if (!pv)
367 pv = g_pfnOrgCalloc(cbItem, cItems);
368 return pv;
369}
370
371/** Replacement for realloc. */
372static void *rtMemReplacementRealloc(void *pvOld, size_t cbNew)
373{
374 if (pvOld)
375 {
376 /* We're not strict about where the memory was allocated. */
377 PRTMEMBLOCK pBlock = rtmemBlockGet(pvOld);
378 if (pBlock)
379 {
380 size_t cbAligned = RTMEM_REPLACMENT_ALIGN(cbNew);
381 return rtR3MemRealloc("r-realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbAligned, "heap", ASMReturnAddress(), RT_SRC_POS);
382 }
383 return g_pfnOrgRealloc(pvOld, cbNew);
384 }
385 return rtMemReplacementMalloc(cbNew);
386}
387
388/** Replacement for free(). */
389static void rtMemReplacementFree(void *pv)
390{
391 if (pv)
392 {
393 /* We're not strict about where the memory was allocated. */
394 PRTMEMBLOCK pBlock = rtmemBlockGet(pv);
395 if (pBlock)
396 rtR3MemFree("r-free", RTMEMTYPE_RTMEMFREE, pv, 0, ASMReturnAddress(), RT_SRC_POS);
397 else
398 g_pfnOrgFree(pv);
399 }
400}
401
402# ifdef RT_OS_DARWIN
403/** Replacement for malloc. */
404static size_t rtMemReplacementMallocSize(void *pv)
405{
406 size_t cb;
407 if (pv)
408 {
409 /* We're not strict about where the memory was allocated. */
410 PRTMEMBLOCK pBlock = rtmemBlockGet(pv);
411 if (pBlock)
412 cb = pBlock->cbUnaligned;
413 else
414 cb = g_pfnOrgMallocSize(pv);
415 }
416 else
417 cb = 0;
418 return cb;
419}
420# endif
421
422
423static void rtMemReplaceMallocAndFriends(void)
424{
425 struct
426 {
427 const char *pszName;
428 PFNRT pfnReplacement;
429 PFNRT pfnOrg;
430 PFNRT *ppfnJumpBack;
431 } aApis[] =
432 {
433 { "free", (PFNRT)rtMemReplacementFree, (PFNRT)free, (PFNRT *)&g_pfnOrgFree },
434 { "realloc", (PFNRT)rtMemReplacementRealloc, (PFNRT)realloc, (PFNRT *)&g_pfnOrgRealloc },
435 { "calloc", (PFNRT)rtMemReplacementCalloc, (PFNRT)calloc, (PFNRT *)&g_pfnOrgCalloc },
436 { "malloc", (PFNRT)rtMemReplacementMalloc, (PFNRT)malloc, (PFNRT *)&g_pfnOrgMalloc },
437#ifdef RT_OS_DARWIN
438 { "malloc_size", (PFNRT)rtMemReplacementMallocSize, (PFNRT)malloc_size, (PFNRT *)&g_pfnOrgMallocSize },
439#endif
440 };
441
442 /*
443 * Initialize the jump backs to avoid recursivly entering this function.
444 */
445 for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
446 *aApis[i].ppfnJumpBack = aApis[i].pfnOrg;
447
448 /*
449 * Give the user an option to skip replacing malloc.
450 */
451 if (getenv("IPRT_DONT_REPLACE_MALLOC"))
452 return;
453
454 /*
455 * Allocate a page for jump back code (we leak it).
456 */
457 uint8_t *pbExecPage = (uint8_t *)RTMemPageAlloc(PAGE_SIZE); AssertFatal(pbExecPage);
458 int rc = RTMemProtect(pbExecPage, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);
459
460 /*
461 * Do the ground work.
462 */
463 uint8_t *pb = pbExecPage;
464 for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
465 {
466 /* Resolve it. */
467 PFNRT pfnOrg = (PFNRT)(uintptr_t)dlsym(RTLD_DEFAULT, aApis[i].pszName);
468 if (pfnOrg)
469 aApis[i].pfnOrg = pfnOrg;
470 else
471 pfnOrg = aApis[i].pfnOrg;
472
473 /* Figure what we can replace and how much to duplicate in the jump back code. */
474# ifdef RT_ARCH_AMD64
475 uint32_t cbNeeded = 12;
476 DISCPUMODE const enmCpuMode = DISCPUMODE_64BIT;
477# elif defined(RT_ARCH_X86)
478 uint32_t const cbNeeded = 5;
479 DISCPUMODE const enmCpuMode = DISCPUMODE_32BIT;
480# else
481# error "Port me"
482# endif
483 uint32_t offJmpBack = 0;
484 uint32_t cbCopy = 0;
485 while (offJmpBack < cbNeeded)
486 {
487 DISCPUSTATE Dis;
488 uint32_t cbInstr = 1;
489 rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
490 AssertFatal(!(Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)));
491# ifdef RT_ARCH_AMD64
492# ifdef RT_OS_DARWIN
493 /* Kludge for: cmp [malloc_def_zone_state], 1; jg 2; call _malloc_initialize; 2: */
494 DISQPVPARAMVAL Parm;
495 if ( Dis.ModRM.Bits.Mod == 0
496 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */
497 && (Dis.Param2.fUse & (DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
498 && Dis.Param2.uValue == 1
499 && Dis.pCurInstr->uOpcode == OP_CMP)
500 {
501 cbCopy = offJmpBack;
502
503 offJmpBack += cbInstr;
504 rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
505 if ( Dis.pCurInstr->uOpcode == OP_JNBE
506 && Dis.Param1.uDisp.i8 == 5)
507 {
508 offJmpBack += cbInstr + 5;
509 AssertFatal(offJmpBack >= cbNeeded);
510 break;
511 }
512 }
513# endif
514 AssertFatal(!(Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */));
515# endif
516 offJmpBack += cbInstr;
517 }
518 if (!cbCopy)
519 cbCopy = offJmpBack;
520
521 /* Assemble the jump back. */
522 memcpy(pb, (void *)(uintptr_t)pfnOrg, cbCopy);
523 uint32_t off = cbCopy;
524# ifdef RT_ARCH_AMD64
525 pb[off++] = 0xff; /* jmp qword [$+8 wrt RIP] */
526 pb[off++] = 0x25;
527 *(uint32_t *)&pb[off] = 0;
528 off += 4;
529 *(uint64_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack;
530 off += 8;
531 off = RT_ALIGN_32(off, 16);
532# elif defined(RT_ARCH_X86)
533 pb[off++] = 0xe9; /* jmp rel32 */
534 *(uint32_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack - (uintptr_t)&pb[4];
535 off += 4;
536 off = RT_ALIGN_32(off, 8);
537# else
538# error "Port me"
539# endif
540 *aApis[i].ppfnJumpBack = (PFNRT)(uintptr_t)pb;
541 pb += off;
542 }
543
544 /*
545 * Modify the APIs.
546 */
547 for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
548 {
549 pb = (uint8_t *)(uintptr_t)aApis[i].pfnOrg;
550 rc = RTMemProtect(pb, 16, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);
551
552# ifdef RT_ARCH_AMD64
553 /* Assemble the LdrLoadDll patch. */
554 *pb++ = 0x48; /* mov rax, qword */
555 *pb++ = 0xb8;
556 *(uint64_t *)pb = (uintptr_t)aApis[i].pfnReplacement;
557 pb += 8;
558 *pb++ = 0xff; /* jmp rax */
559 *pb++ = 0xe0;
560# elif defined(RT_ARCH_X86)
561 *pb++ = 0xe9; /* jmp rel32 */
562 *(uint32_t *)pb = (uintptr_t)aApis[i].pfnReplacement - (uintptr_t)&pb[4];
563# else
564# error "Port me"
565# endif
566 }
567}
568
569#endif /* RTALLOC_REPLACE_MALLOC && RTALLOC_EFENCE_TRACE */
570
571
572/**
573 * Internal allocator.
574 */
575RTDECL(void *) rtR3MemAlloc(const char *pszOp, RTMEMTYPE enmType, size_t cbUnaligned, size_t cbAligned,
576 const char *pszTag, void *pvCaller, RT_SRC_POS_DECL)
577{
578 /*
579 * Sanity.
580 */
581 if ( RT_ALIGN_Z(RTALLOC_EFENCE_SIZE, PAGE_SIZE) != RTALLOC_EFENCE_SIZE
582 && RTALLOC_EFENCE_SIZE <= 0)
583 {
584 rtmemComplain(pszOp, "Invalid E-fence size! %#x\n", RTALLOC_EFENCE_SIZE);
585 return NULL;
586 }
587 if (!cbUnaligned)
588 {
589#if 0
590 rtmemComplain(pszOp, "Request of ZERO bytes allocation!\n");
591 return NULL;
592#else
593 cbAligned = cbUnaligned = 1;
594#endif
595 }
596
597#ifndef RTALLOC_EFENCE_IN_FRONT
598 /* Alignment decreases fence accuracy, but this is at least partially
599 * counteracted by filling and checking the alignment padding. When the
600 * fence is in front then then no extra alignment is needed. */
601 cbAligned = RT_ALIGN_Z(cbAligned, RTALLOC_EFENCE_ALIGNMENT);
602#endif
603
604#ifdef RTALLOC_EFENCE_TRACE
605 /*
606 * Allocate the trace block.
607 */
608 PRTMEMBLOCK pBlock = rtmemBlockCreate(enmType, cbUnaligned, cbAligned, pszTag, pvCaller, RT_SRC_POS_ARGS);
609 if (!pBlock)
610 {
611 rtmemComplain(pszOp, "Failed to allocate trace block!\n");
612 return NULL;
613 }
614#endif
615
616 /*
617 * Allocate a block with page alignment space + the size of the E-fence.
618 */
619 size_t cbBlock = RT_ALIGN_Z(cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
620 void *pvBlock = RTMemPageAlloc(cbBlock);
621 if (pvBlock)
622 {
623 /*
624 * Calc the start of the fence and the user block
625 * and then change the page protection of the fence.
626 */
627#ifdef RTALLOC_EFENCE_IN_FRONT
628 void *pvEFence = pvBlock;
629 void *pv = (char *)pvEFence + RTALLOC_EFENCE_SIZE;
630# ifdef RTALLOC_EFENCE_NOMAN_FILLER
631 memset((char *)pv + cbUnaligned, RTALLOC_EFENCE_NOMAN_FILLER, cbBlock - RTALLOC_EFENCE_SIZE - cbUnaligned);
632# endif
633#else
634 void *pvEFence = (char *)pvBlock + (cbBlock - RTALLOC_EFENCE_SIZE);
635 void *pv = (char *)pvEFence - cbAligned;
636# ifdef RTALLOC_EFENCE_NOMAN_FILLER
637 memset(pvBlock, RTALLOC_EFENCE_NOMAN_FILLER, cbBlock - RTALLOC_EFENCE_SIZE - cbAligned);
638 memset((char *)pv + cbUnaligned, RTALLOC_EFENCE_NOMAN_FILLER, cbAligned - cbUnaligned);
639# endif
640#endif
641
642#ifdef RTALLOC_EFENCE_FENCE_FILLER
643 memset(pvEFence, RTALLOC_EFENCE_FENCE_FILLER, RTALLOC_EFENCE_SIZE);
644#endif
645 int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_NONE);
646 if (!rc)
647 {
648#ifdef RTALLOC_EFENCE_TRACE
649 rtmemBlockInsert(pBlock, pv);
650#endif
651 if (enmType == RTMEMTYPE_RTMEMALLOCZ)
652 memset(pv, 0, cbUnaligned);
653#ifdef RTALLOC_EFENCE_FILLER
654 else
655 memset(pv, RTALLOC_EFENCE_FILLER, cbUnaligned);
656#endif
657
658 rtmemLog(pszOp, "returns %p (pvBlock=%p cbBlock=%#x pvEFence=%p cbUnaligned=%#x)\n", pv, pvBlock, cbBlock, pvEFence, cbUnaligned);
659 return pv;
660 }
661 rtmemComplain(pszOp, "RTMemProtect failed, pvEFence=%p size %d, rc=%d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
662 RTMemPageFree(pvBlock, cbBlock);
663 }
664 else
665 rtmemComplain(pszOp, "Failed to allocated %lu (%lu) bytes.\n", (unsigned long)cbBlock, (unsigned long)cbUnaligned);
666
667#ifdef RTALLOC_EFENCE_TRACE
668 rtmemBlockFree(pBlock);
669#endif
670 return NULL;
671}
672
673
674/**
675 * Internal free.
676 */
677RTDECL(void) rtR3MemFree(const char *pszOp, RTMEMTYPE enmType, void *pv, size_t cbUser, void *pvCaller, RT_SRC_POS_DECL)
678{
679 NOREF(enmType); RT_SRC_POS_NOREF();
680
681 /*
682 * Simple case.
683 */
684 if (!pv)
685 return;
686
687 /*
688 * Check watch points.
689 */
690 for (unsigned i = 0; i < RT_ELEMENTS(gapvRTMemFreeWatch); i++)
691 if (gapvRTMemFreeWatch[i] == pv)
692 RTAssertDoPanic();
693
694#ifdef RTALLOC_EFENCE_TRACE
695 /*
696 * Find the block.
697 */
698 PRTMEMBLOCK pBlock = rtmemBlockRemove(pv);
699 if (pBlock)
700 {
701 if (gfRTMemFreeLog)
702 RTLogPrintf("RTMem %s: pv=%p pvCaller=%p cbUnaligned=%#x\n", pszOp, pv, pvCaller, pBlock->cbUnaligned);
703
704# ifdef RTALLOC_EFENCE_NOMAN_FILLER
705 /*
706 * Check whether the no man's land is untouched.
707 */
708# ifdef RTALLOC_EFENCE_IN_FRONT
709 void *pvWrong = ASMMemFirstMismatchingU8((char *)pv + pBlock->cbUnaligned,
710 RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbUnaligned,
711 RTALLOC_EFENCE_NOMAN_FILLER);
712# else
713 /* Alignment must match allocation alignment in rtMemAlloc(). */
714 void *pvWrong = ASMMemFirstMismatchingU8((char *)pv + pBlock->cbUnaligned,
715 pBlock->cbAligned - pBlock->cbUnaligned,
716 RTALLOC_EFENCE_NOMAN_FILLER);
717 if (pvWrong)
718 RTAssertDoPanic();
719 pvWrong = ASMMemFirstMismatchingU8((void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK),
720 RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbAligned,
721 RTALLOC_EFENCE_NOMAN_FILLER);
722# endif
723 if (pvWrong)
724 RTAssertDoPanic();
725# endif
726
727 /*
728 * Fill the user part of the block.
729 */
730 AssertMsg(enmType != RTMEMTYPE_RTMEMFREEZ || cbUser == pBlock->cbUnaligned,
731 ("cbUser=%#zx cbUnaligned=%#zx\n", cbUser, pBlock->cbUnaligned));
732 RT_NOREF(cbUser);
733 if (enmType == RTMEMTYPE_RTMEMFREEZ)
734 RT_BZERO(pv, pBlock->cbUnaligned);
735# ifdef RTALLOC_EFENCE_FREE_FILL
736 else
737 memset(pv, RTALLOC_EFENCE_FREE_FILL, pBlock->cbUnaligned);
738# endif
739
740# if defined(RTALLOC_EFENCE_FREE_DELAYED) && RTALLOC_EFENCE_FREE_DELAYED > 0
741 /*
742 * We're doing delayed freeing.
743 * That means we'll expand the E-fence to cover the entire block.
744 */
745 int rc = RTMemProtect(pv, pBlock->cbAligned, RTMEM_PROT_NONE);
746 if (RT_SUCCESS(rc))
747 {
748 /*
749 * Insert it into the free list and process pending frees.
750 */
751 rtmemBlockDelayInsert(pBlock);
752 while ((pBlock = rtmemBlockDelayRemove()) != NULL)
753 {
754 pv = pBlock->Core.Key;
755# ifdef RTALLOC_EFENCE_IN_FRONT
756 void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
757# else
758 void *pvBlock = (void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK);
759# endif
760 size_t cbBlock = RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
761 rc = RTMemProtect(pvBlock, cbBlock, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
762 if (RT_SUCCESS(rc))
763 RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE);
764 else
765 rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvBlock, cbBlock, rc);
766 rtmemBlockFree(pBlock);
767 }
768 }
769 else
770 rtmemComplain(pszOp, "Failed to expand the efence of pv=%p cb=%d, rc=%d.\n", pv, pBlock, rc);
771
772# else /* !RTALLOC_EFENCE_FREE_DELAYED */
773
774 /*
775 * Turn of the E-fence and free it.
776 */
777# ifdef RTALLOC_EFENCE_IN_FRONT
778 void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
779 void *pvEFence = pvBlock;
780# else
781 void *pvBlock = (void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK);
782 void *pvEFence = (char *)pv + pBlock->cb;
783# endif
784 int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
785 if (RT_SUCCESS(rc))
786 RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE);
787 else
788 rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
789 rtmemBlockFree(pBlock);
790
791# endif /* !RTALLOC_EFENCE_FREE_DELAYED */
792 }
793 else
794 rtmemComplain(pszOp, "pv=%p not found! Incorrect free!\n", pv);
795
796#else /* !RTALLOC_EFENCE_TRACE */
797
798 /*
799 * We have no size tracking, so we're not doing any freeing because
800 * we cannot if the E-fence is after the block.
801 * Let's just expand the E-fence to the first page of the user bit
802 * since we know that it's around.
803 */
804 if (enmType == RTMEMTYPE_RTMEMFREEZ)
805 RT_BZERO(pv, cbUser);
806 int rc = RTMemProtect((void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK), PAGE_SIZE, RTMEM_PROT_NONE);
807 if (RT_FAILURE(rc))
808 rtmemComplain(pszOp, "RTMemProtect(%p, PAGE_SIZE, RTMEM_PROT_NONE) -> %d\n", (void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK), rc);
809#endif /* !RTALLOC_EFENCE_TRACE */
810}
811
812
813/**
814 * Internal realloc.
815 */
816RTDECL(void *) rtR3MemRealloc(const char *pszOp, RTMEMTYPE enmType, void *pvOld, size_t cbNew,
817 const char *pszTag, void *pvCaller, RT_SRC_POS_DECL)
818{
819 /*
820 * Allocate new and copy.
821 */
822 if (!pvOld)
823 return rtR3MemAlloc(pszOp, enmType, cbNew, cbNew, pszTag, pvCaller, RT_SRC_POS_ARGS);
824 if (!cbNew)
825 {
826 rtR3MemFree(pszOp, RTMEMTYPE_RTMEMREALLOC, pvOld, 0, pvCaller, RT_SRC_POS_ARGS);
827 return NULL;
828 }
829
830#ifdef RTALLOC_EFENCE_TRACE
831
832 /*
833 * Get the block, allocate the new, copy the data, free the old one.
834 */
835 PRTMEMBLOCK pBlock = rtmemBlockGet(pvOld);
836 if (pBlock)
837 {
838 void *pvRet = rtR3MemAlloc(pszOp, enmType, cbNew, cbNew, pszTag, pvCaller, RT_SRC_POS_ARGS);
839 if (pvRet)
840 {
841 memcpy(pvRet, pvOld, RT_MIN(cbNew, pBlock->cbUnaligned));
842 rtR3MemFree(pszOp, RTMEMTYPE_RTMEMREALLOC, pvOld, 0, pvCaller, RT_SRC_POS_ARGS);
843 }
844 return pvRet;
845 }
846 else
847 rtmemComplain(pszOp, "pvOld=%p was not found!\n", pvOld);
848 return NULL;
849
850#else /* !RTALLOC_EFENCE_TRACE */
851
852 rtmemComplain(pszOp, "Not supported if RTALLOC_EFENCE_TRACE isn't defined!\n");
853 return NULL;
854
855#endif /* !RTALLOC_EFENCE_TRACE */
856}
857
858
859
860
861RTDECL(void *) RTMemEfTmpAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
862{
863 return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
864}
865
866
867RTDECL(void *) RTMemEfTmpAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
868{
869 return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
870}
871
872
873RTDECL(void) RTMemEfTmpFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_DEF
874{
875 if (pv)
876 rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, 0, ASMReturnAddress(), RT_SRC_POS_ARGS);
877}
878
879
880RTDECL(void) RTMemEfTmpFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_DEF
881{
882 if (pv)
883 rtR3MemFree("FreeZ", RTMEMTYPE_RTMEMFREEZ, pv, cb, ASMReturnAddress(), RT_SRC_POS_ARGS);
884}
885
886
887RTDECL(void *) RTMemEfAlloc(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
888{
889 return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
890}
891
892
893RTDECL(void *) RTMemEfAllocZ(size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
894{
895 return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
896}
897
898
899RTDECL(void *) RTMemEfAllocVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
900{
901 size_t cbAligned;
902 if (cbUnaligned >= 16)
903 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
904 else
905 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
906 return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
907}
908
909
910RTDECL(void *) RTMemEfAllocZVar(size_t cbUnaligned, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
911{
912 size_t cbAligned;
913 if (cbUnaligned >= 16)
914 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
915 else
916 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
917 return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
918}
919
920
921RTDECL(void *) RTMemEfRealloc(void *pvOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
922{
923 return rtR3MemRealloc("Realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
924}
925
926
927RTDECL(void *) RTMemEfReallocZ(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
928{
929 void *pvDst = rtR3MemRealloc("ReallocZ", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), RT_SRC_POS_ARGS);
930 if (pvDst && cbNew > cbOld)
931 memset((uint8_t *)pvDst + cbOld, 0, cbNew - cbOld);
932 return pvDst;
933}
934
935
936RTDECL(void) RTMemEfFree(void *pv, RT_SRC_POS_DECL) RT_NO_THROW_DEF
937{
938 if (pv)
939 rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, 0, ASMReturnAddress(), RT_SRC_POS_ARGS);
940}
941
942
943RTDECL(void) RTMemEfFreeZ(void *pv, size_t cb, RT_SRC_POS_DECL) RT_NO_THROW_DEF
944{
945 if (pv)
946 rtR3MemFree("FreeZ", RTMEMTYPE_RTMEMFREEZ, pv, cb, ASMReturnAddress(), RT_SRC_POS_ARGS);
947}
948
949
950RTDECL(void *) RTMemEfDup(const void *pvSrc, size_t cb, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
951{
952 void *pvDst = RTMemEfAlloc(cb, pszTag, RT_SRC_POS_ARGS);
953 if (pvDst)
954 memcpy(pvDst, pvSrc, cb);
955 return pvDst;
956}
957
958
959RTDECL(void *) RTMemEfDupEx(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag, RT_SRC_POS_DECL) RT_NO_THROW_DEF
960{
961 void *pvDst = RTMemEfAlloc(cbSrc + cbExtra, pszTag, RT_SRC_POS_ARGS);
962 if (pvDst)
963 {
964 memcpy(pvDst, pvSrc, cbSrc);
965 memset((uint8_t *)pvDst + cbSrc, 0, cbExtra);
966 }
967 return pvDst;
968}
969
970
971
972
973/*
974 *
975 * The NP (no position) versions.
976 *
977 */
978
979
980
981RTDECL(void *) RTMemEfTmpAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_DEF
982{
983 return rtR3MemAlloc("TmpAlloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
984}
985
986
987RTDECL(void *) RTMemEfTmpAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_DEF
988{
989 return rtR3MemAlloc("TmpAllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
990}
991
992
993RTDECL(void) RTMemEfTmpFreeNP(void *pv) RT_NO_THROW_DEF
994{
995 if (pv)
996 rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, 0, ASMReturnAddress(), NULL, 0, NULL);
997}
998
999
1000RTDECL(void) RTMemEfTmpFreeZNP(void *pv, size_t cb) RT_NO_THROW_DEF
1001{
1002 if (pv)
1003 rtR3MemFree("FreeZ", RTMEMTYPE_RTMEMFREEZ, pv, cb, ASMReturnAddress(), NULL, 0, NULL);
1004}
1005
1006
1007RTDECL(void *) RTMemEfAllocNP(size_t cb, const char *pszTag) RT_NO_THROW_DEF
1008{
1009 return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1010}
1011
1012
1013RTDECL(void *) RTMemEfAllocZNP(size_t cb, const char *pszTag) RT_NO_THROW_DEF
1014{
1015 return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, cb, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1016}
1017
1018
1019RTDECL(void *) RTMemEfAllocVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_DEF
1020{
1021 size_t cbAligned;
1022 if (cbUnaligned >= 16)
1023 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
1024 else
1025 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
1026 return rtR3MemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1027}
1028
1029
1030RTDECL(void *) RTMemEfAllocZVarNP(size_t cbUnaligned, const char *pszTag) RT_NO_THROW_DEF
1031{
1032 size_t cbAligned;
1033 if (cbUnaligned >= 16)
1034 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
1035 else
1036 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
1037 return rtR3MemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cbUnaligned, cbAligned, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1038}
1039
1040
1041RTDECL(void *) RTMemEfReallocNP(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
1042{
1043 return rtR3MemRealloc("Realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1044}
1045
1046
1047RTDECL(void *) RTMemEfReallocZNP(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
1048{
1049 void *pvDst = rtR3MemRealloc("ReallocZ", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, pszTag, ASMReturnAddress(), NULL, 0, NULL);
1050 if (pvDst && cbNew > cbOld)
1051 memset((uint8_t *)pvDst + cbOld, 0, cbNew - cbOld);
1052 return pvDst;
1053}
1054
1055
1056RTDECL(void) RTMemEfFreeNP(void *pv) RT_NO_THROW_DEF
1057{
1058 if (pv)
1059 rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, 0, ASMReturnAddress(), NULL, 0, NULL);
1060}
1061
1062
1063RTDECL(void) RTMemEfFreeZNP(void *pv, size_t cb) RT_NO_THROW_DEF
1064{
1065 if (pv)
1066 rtR3MemFree("Free", RTMEMTYPE_RTMEMFREEZ, pv, cb, ASMReturnAddress(), NULL, 0, NULL);
1067}
1068
1069
1070RTDECL(void *) RTMemEfDupNP(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_DEF
1071{
1072 void *pvDst = RTMemEfAlloc(cb, pszTag, NULL, 0, NULL);
1073 if (pvDst)
1074 memcpy(pvDst, pvSrc, cb);
1075 return pvDst;
1076}
1077
1078
1079RTDECL(void *) RTMemEfDupExNP(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_DEF
1080{
1081 void *pvDst = RTMemEfAlloc(cbSrc + cbExtra, pszTag, NULL, 0, NULL);
1082 if (pvDst)
1083 {
1084 memcpy(pvDst, pvSrc, cbSrc);
1085 memset((uint8_t *)pvDst + cbSrc, 0, cbExtra);
1086 }
1087 return pvDst;
1088}
1089
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use