VirtualBox

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

Last change on this file since 27575 was 27575, checked in by vboxsync, 15 years ago

alloc-ef.cpp: sensible variable names.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.2 KB
Line 
1/* $Id: alloc-ef.cpp 27575 2010-03-22 09:37:43Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, electric fence.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "alloc-ef.h"
36#include <iprt/log.h>
37#include <iprt/asm.h>
38#include <iprt/thread.h>
39#include <VBox/sup.h>
40#include <iprt/err.h>
41#include <errno.h>
42#include <stdio.h>
43#include <stdlib.h>
44
45#include <iprt/alloc.h>
46#include <iprt/assert.h>
47#include <iprt/param.h>
48#include <iprt/string.h>
49
50
51/*******************************************************************************
52* Global Variables *
53*******************************************************************************/
54#ifdef RTALLOC_EFENCE_TRACE
55/** Spinlock protecting the allthe blocks globals. */
56static volatile uint32_t g_BlocksLock;
57/** Tree tracking the allocations. */
58static AVLPVTREE g_BlocksTree;
59#ifdef RTALLOC_EFENCE_FREE_DELAYED
60/** Tail of the delayed blocks. */
61static volatile PRTMEMBLOCK g_pBlocksDelayHead;
62/** Tail of the delayed blocks. */
63static volatile PRTMEMBLOCK g_pBlocksDelayTail;
64/** Number of bytes in the delay list (includes fences). */
65static volatile size_t g_cbBlocksDelay;
66#endif
67#endif
68/** Array of pointers free watches for. */
69void *gapvRTMemFreeWatch[4] = {NULL, NULL, NULL, NULL};
70/** Enable logging of all freed memory. */
71bool gfRTMemFreeLog = false;
72
73
74/*******************************************************************************
75* Internal Functions *
76*******************************************************************************/
77/**
78 * Complains about something.
79 */
80static void rtmemComplain(const char *pszOp, const char *pszFormat, ...)
81{
82 va_list args;
83 fprintf(stderr, "RTMem error: %s: ", pszOp);
84 va_start(args, pszFormat);
85 vfprintf(stderr, pszFormat, args);
86 va_end(args);
87 RTAssertDoPanic();
88}
89
90/**
91 * Log an event.
92 */
93static inline void rtmemLog(const char *pszOp, const char *pszFormat, ...)
94{
95#if 0
96 va_list args;
97 fprintf(stderr, "RTMem info: %s: ", pszOp);
98 va_start(args, pszFormat);
99 vfprintf(stderr, pszFormat, args);
100 va_end(args);
101#endif
102}
103
104
105#ifdef RTALLOC_EFENCE_TRACE
106
107/**
108 * Aquires the lock.
109 */
110static inline void rtmemBlockLock(void)
111{
112 unsigned c = 0;
113 while (!ASMAtomicCmpXchgU32(&g_BlocksLock, 1, 0))
114 RTThreadSleep(((++c) >> 2) & 31);
115}
116
117
118/**
119 * Releases the lock.
120 */
121static inline void rtmemBlockUnlock(void)
122{
123 Assert(g_BlocksLock == 1);
124 ASMAtomicXchgU32(&g_BlocksLock, 0);
125}
126
127
128/**
129 * Creates a block.
130 */
131static inline PRTMEMBLOCK rtmemBlockCreate(RTMEMTYPE enmType, size_t cb, void *pvCaller, unsigned iLine, const char *pszFile, const char *pszFunction)
132{
133 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)malloc(sizeof(*pBlock));
134 if (pBlock)
135 {
136 pBlock->enmType = enmType;
137 pBlock->cb = cb;
138 pBlock->pvCaller = pvCaller;
139 pBlock->iLine = iLine;
140 pBlock->pszFile = pszFile;
141 pBlock->pszFunction = pszFunction;
142 }
143 return pBlock;
144}
145
146
147/**
148 * Frees a block.
149 */
150static inline void rtmemBlockFree(PRTMEMBLOCK pBlock)
151{
152 free(pBlock);
153}
154
155
156/**
157 * Insert a block from the tree.
158 */
159static inline void rtmemBlockInsert(PRTMEMBLOCK pBlock, void *pv)
160{
161 pBlock->Core.Key = pv;
162 rtmemBlockLock();
163 bool fRc = RTAvlPVInsert(&g_BlocksTree, &pBlock->Core);
164 rtmemBlockUnlock();
165 AssertRelease(fRc);
166}
167
168
169/**
170 * Remove a block from the tree and returns it to the caller.
171 */
172static inline PRTMEMBLOCK rtmemBlockRemove(void *pv)
173{
174 rtmemBlockLock();
175 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)RTAvlPVRemove(&g_BlocksTree, pv);
176 rtmemBlockUnlock();
177 return pBlock;
178}
179
180/**
181 * Gets a block.
182 */
183static inline PRTMEMBLOCK rtmemBlockGet(void *pv)
184{
185 rtmemBlockLock();
186 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)RTAvlPVGet(&g_BlocksTree, pv);
187 rtmemBlockUnlock();
188 return pBlock;
189}
190
191/**
192 * Dumps one allocation.
193 */
194static DECLCALLBACK(int) RTMemDumpOne(PAVLPVNODECORE pNode, void *pvUser)
195{
196 PRTMEMBLOCK pBlock = (PRTMEMBLOCK)pNode;
197 fprintf(stderr, "%p %08lx %p\n",
198 pBlock->Core.Key,
199 (long)pBlock->cb,
200 pBlock->pvCaller);
201 return 0;
202}
203
204/**
205 * Dumps the allocated blocks.
206 * This is something which you should call from gdb.
207 */
208extern "C" void RTMemDump(void);
209void RTMemDump(void)
210{
211 fprintf(stderr, "address size caller\n");
212 RTAvlPVDoWithAll(&g_BlocksTree, true, RTMemDumpOne, NULL);
213}
214
215
216#ifdef RTALLOC_EFENCE_FREE_DELAYED
217/**
218 * Insert a delayed block.
219 */
220static inline void rtmemBlockDelayInsert(PRTMEMBLOCK pBlock)
221{
222 size_t cbBlock = RT_ALIGN_Z(pBlock->cb, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
223 pBlock->Core.pRight = NULL;
224 pBlock->Core.pLeft = NULL;
225 rtmemBlockLock();
226 if (g_pBlocksDelayHead)
227 {
228 g_pBlocksDelayHead->Core.pLeft = (PAVLPVNODECORE)pBlock;
229 pBlock->Core.pRight = (PAVLPVNODECORE)g_pBlocksDelayHead;
230 g_pBlocksDelayHead = pBlock;
231 }
232 else
233 {
234 g_pBlocksDelayTail = pBlock;
235 g_pBlocksDelayHead = pBlock;
236 }
237 g_cbBlocksDelay += cbBlock;
238 rtmemBlockUnlock();
239}
240
241/**
242 * Removes a delayed block.
243 */
244static inline PRTMEMBLOCK rtmemBlockDelayRemove(void)
245{
246 PRTMEMBLOCK pBlock = NULL;
247 rtmemBlockLock();
248 if (g_cbBlocksDelay > RTALLOC_EFENCE_FREE_DELAYED)
249 {
250 pBlock = g_pBlocksDelayTail;
251 if (pBlock)
252 {
253 g_pBlocksDelayTail = (PRTMEMBLOCK)pBlock->Core.pLeft;
254 if (pBlock->Core.pLeft)
255 pBlock->Core.pLeft->pRight = NULL;
256 else
257 g_pBlocksDelayHead = NULL;
258 g_cbBlocksDelay -= RT_ALIGN_Z(pBlock->cb, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
259 }
260 }
261 rtmemBlockUnlock();
262 return pBlock;
263}
264
265
266#endif /* DELAY */
267
268#endif /* RTALLOC_EFENCE_TRACE */
269
270
271/**
272 * Internal allocator.
273 */
274void *rtMemAlloc(const char *pszOp, RTMEMTYPE enmType, size_t cb, void *pvCaller, unsigned iLine, const char *pszFile, const char *pszFunction)
275{
276 /*
277 * Sanity.
278 */
279 if ( RT_ALIGN_Z(RTALLOC_EFENCE_SIZE, PAGE_SIZE) != RTALLOC_EFENCE_SIZE
280 && RTALLOC_EFENCE_SIZE <= 0)
281 {
282 rtmemComplain(pszOp, "Invalid E-fence size! %#x\n", RTALLOC_EFENCE_SIZE);
283 return NULL;
284 }
285 if (!cb)
286 {
287#if 0
288 rtmemComplain(pszOp, "Request of ZERO bytes allocation!\n");
289 return NULL;
290#else
291 cb = 1;
292#endif
293 }
294#ifndef RTALLOC_EFENCE_IN_FRONT
295 /* Alignment decreases fence accuracy, but this is at least partially
296 * counteracted by filling and checking the alignment padding. When the
297 * fence is in front then then no extra alignment is needed. */
298 size_t cbAligned = RT_ALIGN_Z(cb, RTALLOC_EFENCE_ALIGNMENT);
299#endif
300
301#ifdef RTALLOC_EFENCE_TRACE
302 /*
303 * Allocate the trace block.
304 */
305 PRTMEMBLOCK pBlock = rtmemBlockCreate(enmType, cb, pvCaller, iLine, pszFile, pszFunction);
306 if (!pBlock)
307 {
308 rtmemComplain(pszOp, "Failed to allocate trace block!\n");
309 return NULL;
310 }
311#endif
312
313 /*
314 * Allocate a block with page alignment space + the size of the E-fence.
315 */
316 size_t cbBlock = RT_ALIGN_Z(cb, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
317 void *pvBlock = RTMemPageAlloc(cbBlock);
318 if (pvBlock)
319 {
320 /*
321 * Calc the start of the fence and the user block
322 * and then change the page protection of the fence.
323 */
324 #ifdef RTALLOC_EFENCE_IN_FRONT
325 void *pvEFence = pvBlock;
326 void *pv = (char *)pvEFence + RTALLOC_EFENCE_SIZE;
327# ifdef RTALLOC_EFENCE_NOMAN_FILLER
328 memset((char *)pv + cb, RTALLOC_EFENCE_NOMAN_FILLER, cbBlock - RTALLOC_EFENCE_SIZE - cb);
329# endif
330 #else
331 void *pvEFence = (char *)pvBlock + (cbBlock - RTALLOC_EFENCE_SIZE);
332 void *pv = (char *)pvEFence - cbAligned;
333# ifdef RTALLOC_EFENCE_NOMAN_FILLER
334 memset(pvBlock, RTALLOC_EFENCE_NOMAN_FILLER, cbBlock - RTALLOC_EFENCE_SIZE - cbAligned);
335 memset((char *)pv + cb, RTALLOC_EFENCE_NOMAN_FILLER, cbAligned - cb);
336# endif
337 #endif
338
339#ifdef RTALLOC_EFENCE_FENCE_FILLER
340 memset(pvEFence, RTALLOC_EFENCE_FENCE_FILLER, RTALLOC_EFENCE_SIZE);
341#endif
342 int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_NONE);
343 if (!rc)
344 {
345 #ifdef RTALLOC_EFENCE_TRACE
346 rtmemBlockInsert(pBlock, pv);
347 #endif
348 if (enmType == RTMEMTYPE_RTMEMALLOCZ)
349 memset(pv, 0, cb);
350#ifdef RTALLOC_EFENCE_FILLER
351 else
352 memset(pv, RTALLOC_EFENCE_FILLER, cb);
353#endif
354
355 rtmemLog(pszOp, "returns %p (pvBlock=%p cbBlock=%#x pvEFence=%p cb=%#x)\n", pv, pvBlock, cbBlock, pvEFence, cb);
356 return pv;
357 }
358 rtmemComplain(pszOp, "RTMemProtect failed, pvEFence=%p size %d, rc=%d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
359 RTMemPageFree(pvBlock);
360 }
361 else
362 rtmemComplain(pszOp, "Failed to allocated %d bytes.\n", cb);
363
364#ifdef RTALLOC_EFENCE_TRACE
365 rtmemBlockFree(pBlock);
366#endif
367 return NULL;
368}
369
370
371/**
372 * Internal free.
373 */
374void rtMemFree(const char *pszOp, RTMEMTYPE enmType, void *pv, void *pvCaller, unsigned iLine, const char *pszFile, const char *pszFunction)
375{
376 /*
377 * Simple case.
378 */
379 if (!pv)
380 return;
381
382 /*
383 * Check watch points.
384 */
385 for (unsigned i = 0; i < RT_ELEMENTS(gapvRTMemFreeWatch); i++)
386 if (gapvRTMemFreeWatch[i] == pv)
387 RTAssertDoPanic();
388
389#ifdef RTALLOC_EFENCE_TRACE
390 /*
391 * Find the block.
392 */
393 PRTMEMBLOCK pBlock = rtmemBlockRemove(pv);
394 if (pBlock)
395 {
396 if (gfRTMemFreeLog)
397 RTLogPrintf("RTMem %s: pv=%p pvCaller=%p cb=%#x\n", pszOp, pv, pvCaller, pBlock->cb);
398
399#ifdef RTALLOC_EFENCE_NOMAN_FILLER
400 /*
401 * Check whether the no man's land is untouched.
402 */
403# ifdef RTALLOC_EFENCE_IN_FRONT
404 void *pvWrong = ASMMemIsAll8((char *)pv + pBlock->cb,
405 RT_ALIGN_Z(pBlock->cb, PAGE_SIZE) - pBlock->cb,
406 RTALLOC_EFENCE_NOMAN_FILLER);
407# else
408 /* Alignment must match allocation alignment in rtMemAlloc(). */
409 size_t cbAligned = RT_ALIGN_Z(pBlock->cb, RTALLOC_EFENCE_ALIGNMENT);
410 void *pvWrong = ASMMemIsAll8((char *)pv + pBlock->cb,
411 cbAligned - pBlock->cb,
412 RTALLOC_EFENCE_NOMAN_FILLER);
413 if (pvWrong)
414 RTAssertDoPanic();
415 pvWrong = ASMMemIsAll8((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK),
416 RT_ALIGN_Z(cbAligned, PAGE_SIZE) - cbAligned,
417 RTALLOC_EFENCE_NOMAN_FILLER);
418# endif
419 if (pvWrong)
420 RTAssertDoPanic();
421#endif
422
423 #ifdef RTALLOC_EFENCE_FREE_FILL
424 /*
425 * Fill the user part of the block.
426 */
427 memset(pv, RTALLOC_EFENCE_FREE_FILL, pBlock->cb);
428 #endif
429
430 #if defined(RTALLOC_EFENCE_FREE_DELAYED) && RTALLOC_EFENCE_FREE_DELAYED > 0
431 /*
432 * We're doing delayed freeing.
433 * That means we'll expand the E-fence to cover the entire block.
434 */
435 int rc = RTMemProtect(pv, pBlock->cb, RTMEM_PROT_NONE);
436 if (RT_SUCCESS(rc))
437 {
438 /*
439 * Insert it into the free list and process pending frees.
440 */
441 rtmemBlockDelayInsert(pBlock);
442 while ((pBlock = rtmemBlockDelayRemove()) != NULL)
443 {
444 pv = pBlock->Core.Key;
445 #ifdef RTALLOC_EFENCE_IN_FRONT
446 void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
447 #else
448 void *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
449 #endif
450 size_t cbBlock = RT_ALIGN_Z(pBlock->cb, PAGE_SIZE) + RTALLOC_EFENCE_SIZE;
451 rc = RTMemProtect(pvBlock, cbBlock, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
452 if (RT_SUCCESS(rc))
453 RTMemPageFree(pvBlock);
454 else
455 rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvBlock, cbBlock, rc);
456 rtmemBlockFree(pBlock);
457 }
458 }
459 else
460 rtmemComplain(pszOp, "Failed to expand the efence of pv=%p cb=%d, rc=%d.\n", pv, pBlock, rc);
461
462 #else /* !RTALLOC_EFENCE_FREE_DELAYED */
463
464 /*
465 * Turn of the E-fence and free it.
466 */
467 #ifdef RTALLOC_EFENCE_IN_FRONT
468 void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE;
469 void *pvEFence = pvBlock;
470 #else
471 void *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
472 void *pvEFence = (char *)pv + pBlock->cb;
473 #endif
474 int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
475 if (RT_SUCCESS(rc))
476 RTMemPageFree(pvBlock);
477 else
478 rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc);
479 rtmemBlockFree(pBlock);
480
481 #endif /* !RTALLOC_EFENCE_FREE_DELAYED */
482 }
483 else
484 rtmemComplain(pszOp, "pv=%p not found! Incorrect free!\n", pv);
485
486#else /* !RTALLOC_EFENCE_TRACE */
487
488 /*
489 * We have no size tracking, so we're not doing any freeing because
490 * we cannot if the E-fence is after the block.
491 * Let's just expand the E-fence to the first page of the user bit
492 * since we know that it's around.
493 */
494 int rc = RTMemProtect((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), PAGE_SIZE, RTMEM_PROT_NONE);
495 if (RT_FAILURE(rc))
496 rtmemComplain(pszOp, "RTMemProtect(%p, PAGE_SIZE, RTMEM_PROT_NONE) -> %d\n", (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), rc);
497#endif /* !RTALLOC_EFENCE_TRACE */
498}
499
500/**
501 * Internal realloc.
502 */
503void *rtMemRealloc(const char *pszOp, RTMEMTYPE enmType, void *pvOld, size_t cbNew, void *pvCaller, unsigned iLine, const char *pszFile, const char *pszFunction)
504{
505 /*
506 * Allocate new and copy.
507 */
508 if (!pvOld)
509 return rtMemAlloc(pszOp, enmType, cbNew, pvCaller, iLine, pszFile, pszFunction);
510 if (!cbNew)
511 {
512 rtMemFree(pszOp, RTMEMTYPE_RTMEMREALLOC, pvOld, pvCaller, iLine, pszFile, pszFunction);
513 return NULL;
514 }
515
516#ifdef RTALLOC_EFENCE_TRACE
517
518 /*
519 * Get the block, allocate the new, copy the data, free the old one.
520 */
521 PRTMEMBLOCK pBlock = rtmemBlockGet(pvOld);
522 if (pBlock)
523 {
524 void *pvRet = rtMemAlloc(pszOp, enmType, cbNew, pvCaller, iLine, pszFile, pszFunction);
525 if (pvRet)
526 {
527 memcpy(pvRet, pvOld, RT_MIN(cbNew, pBlock->cb));
528 rtMemFree(pszOp, RTMEMTYPE_RTMEMREALLOC, pvOld, pvCaller, iLine, pszFile, pszFunction);
529 }
530 return pvRet;
531 }
532 else
533 rtmemComplain(pszOp, "pvOld=%p was not found!\n", pvOld);
534 return NULL;
535
536#else /* !RTALLOC_EFENCE_TRACE */
537
538 rtmemComplain(pszOp, "Not supported if RTALLOC_EFENCE_TRACE isn't defined!\n");
539 return NULL;
540
541#endif /* !RTALLOC_EFENCE_TRACE */
542}
543
544
545
546
547/**
548 * Same as RTMemTmpAlloc() except that it's fenced.
549 *
550 * @returns Pointer to the allocated memory.
551 * @returns NULL on failure.
552 * @param cb Size in bytes of the memory block to allocate.
553 */
554RTDECL(void *) RTMemEfTmpAlloc(size_t cb) RT_NO_THROW
555{
556 return RTMemEfAlloc(cb);
557}
558
559
560/**
561 * Same as RTMemTmpAllocZ() except that it's fenced.
562 *
563 * @returns Pointer to the allocated memory.
564 * @returns NULL on failure.
565 * @param cb Size in bytes of the memory block to allocate.
566 */
567RTDECL(void *) RTMemEfTmpAllocZ(size_t cb) RT_NO_THROW
568{
569 return RTMemEfAllocZ(cb);
570}
571
572
573/**
574 * Same as RTMemTmpFree() except that it's for fenced memory.
575 *
576 * @param pv Pointer to memory block.
577 */
578RTDECL(void) RTMemEfTmpFree(void *pv) RT_NO_THROW
579{
580 RTMemEfFree(pv);
581}
582
583
584/**
585 * Same as RTMemAlloc() except that it's fenced.
586 *
587 * @returns Pointer to the allocated memory. Free with RTMemEfFree().
588 * @returns NULL on failure.
589 * @param cb Size in bytes of the memory block to allocate.
590 */
591RTDECL(void *) RTMemEfAlloc(size_t cb) RT_NO_THROW
592{
593 return rtMemAlloc("Alloc", RTMEMTYPE_RTMEMALLOC, cb, ((void **)&cb)[-1], 0, NULL, NULL);
594}
595
596
597/**
598 * Same as RTMemAllocZ() except that it's fenced.
599 *
600 * @returns Pointer to the allocated memory.
601 * @returns NULL on failure.
602 * @param cb Size in bytes of the memory block to allocate.
603 */
604RTDECL(void *) RTMemEfAllocZ(size_t cb) RT_NO_THROW
605{
606 return rtMemAlloc("AllocZ", RTMEMTYPE_RTMEMALLOCZ, cb, ((void **)&cb)[-1], 0, NULL, NULL);
607}
608
609
610/**
611 * Same as RTMemRealloc() except that it's fenced.
612 *
613 * @returns Pointer to the allocated memory.
614 * @returns NULL on failure.
615 * @param pvOld The memory block to reallocate.
616 * @param cbNew The new block size (in bytes).
617 */
618RTDECL(void *) RTMemEfRealloc(void *pvOld, size_t cbNew) RT_NO_THROW
619{
620 return rtMemRealloc("Realloc", RTMEMTYPE_RTMEMREALLOC, pvOld, cbNew, ((void **)&pvOld)[-1], 0, NULL, NULL);
621}
622
623
624/**
625 * Free memory allocated by any of the RTMemEf* allocators.
626 *
627 * @param pv Pointer to memory block.
628 */
629RTDECL(void) RTMemEfFree(void *pv) RT_NO_THROW
630{
631 if (pv)
632 rtMemFree("Free", RTMEMTYPE_RTMEMFREE, pv, ((void **)&pv)[-1], 0, NULL, NULL);
633}
634
635
636/**
637 * Same as RTMemDup() except that it's fenced.
638 *
639 * @returns New heap block with the duplicate data.
640 * @returns NULL if we're out of memory.
641 * @param pvSrc The memory to duplicate.
642 * @param cb The amount of memory to duplicate.
643 */
644RTDECL(void *) RTMemEfDup(const void *pvSrc, size_t cb) RT_NO_THROW
645{
646 void *pvDst = RTMemEfAlloc(cb);
647 if (pvDst)
648 memcpy(pvDst, pvSrc, cb);
649 return pvDst;
650}
651
652
653/**
654 * Same as RTMemDupEx except that it's fenced.
655 *
656 * @returns New heap block with the duplicate data.
657 * @returns NULL if we're out of memory.
658 * @param pvSrc The memory to duplicate.
659 * @param cbSrc The amount of memory to duplicate.
660 * @param cbExtra The amount of extra memory to allocate and zero.
661 */
662RTDECL(void *) RTMemEfDupEx(const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW
663{
664 void *pvDst = RTMemEfAlloc(cbSrc + cbExtra);
665 if (pvDst)
666 {
667 memcpy(pvDst, pvSrc, cbSrc);
668 memset((uint8_t *)pvDst + cbSrc, 0, cbExtra);
669 }
670 return pvDst;
671}
672
Note: See TracBrowser for help on using the repository browser.

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