VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/MMHeap.cpp@ 84044

Last change on this file since 84044 was 83564, checked in by vboxsync, 4 years ago

VMM/MMR3Heap: Zero on free and realloc. Always unlink _before_ realloc. bugref:9698

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.7 KB
Line 
1/* $Id: MMHeap.cpp 83564 2020-04-05 14:14:13Z vboxsync $ */
2/** @file
3 * MM - Memory Manager - Heap.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MM_HEAP
23#include <VBox/vmm/mm.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/vmm/pgm.h>
26#include "MMInternal.h"
27#include <VBox/vmm/vm.h>
28#include <VBox/vmm/uvm.h>
29#include <iprt/errcore.h>
30#include <VBox/param.h>
31#include <VBox/log.h>
32
33#include <iprt/alloc.h>
34#include <iprt/assert.h>
35#include <iprt/string.h>
36
37
38/*********************************************************************************************************************************
39* Internal Functions *
40*********************************************************************************************************************************/
41static void *mmR3HeapAlloc(PMMHEAP pHeap, MMTAG enmTag, size_t cbSize, bool fZero);
42
43
44
45/**
46 * Allocate and initialize a heap structure and it's associated substructures.
47 *
48 * @returns VBox status code.
49 * @param pUVM Pointer to the user mode VM structure.
50 * @param ppHeap Where to store the heap pointer.
51 */
52int mmR3HeapCreateU(PUVM pUVM, PMMHEAP *ppHeap)
53{
54 PMMHEAP pHeap = (PMMHEAP)RTMemAllocZ(sizeof(MMHEAP) + sizeof(MMHEAPSTAT));
55 if (pHeap)
56 {
57 int rc = RTCritSectInit(&pHeap->Lock);
58 if (RT_SUCCESS(rc))
59 {
60 /*
61 * Initialize the global stat record.
62 */
63 pHeap->pUVM = pUVM;
64 pHeap->Stat.pHeap = pHeap;
65#ifdef MMR3HEAP_WITH_STATISTICS
66 PMMHEAPSTAT pStat = &pHeap->Stat;
67 STAMR3RegisterU(pUVM, &pStat->cAllocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cAllocations", STAMUNIT_CALLS, "Number or MMR3HeapAlloc() calls.");
68 STAMR3RegisterU(pUVM, &pStat->cReallocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cReallocations", STAMUNIT_CALLS, "Number of MMR3HeapRealloc() calls.");
69 STAMR3RegisterU(pUVM, &pStat->cFrees, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cFrees", STAMUNIT_CALLS, "Number of MMR3HeapFree() calls.");
70 STAMR3RegisterU(pUVM, &pStat->cFailures, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cFailures", STAMUNIT_COUNT, "Number of failures.");
71 STAMR3RegisterU(pUVM, &pStat->cbCurAllocated, sizeof(pStat->cbCurAllocated) == sizeof(uint32_t) ? STAMTYPE_U32 : STAMTYPE_U64,
72 STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbCurAllocated", STAMUNIT_BYTES, "Number of bytes currently allocated.");
73 STAMR3RegisterU(pUVM, &pStat->cbAllocated, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbAllocated", STAMUNIT_BYTES, "Total number of bytes allocated.");
74 STAMR3RegisterU(pUVM, &pStat->cbFreed, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbFreed", STAMUNIT_BYTES, "Total number of bytes freed.");
75#endif
76 *ppHeap = pHeap;
77 return VINF_SUCCESS;
78 }
79 AssertRC(rc);
80 RTMemFree(pHeap);
81 }
82 AssertMsgFailed(("failed to allocate heap structure\n"));
83 return VERR_NO_MEMORY;
84}
85
86
87/**
88 * MM heap statistics tree destroy callback.
89 */
90static DECLCALLBACK(int) mmR3HeapStatTreeDestroy(PAVLULNODECORE pCore, void *pvParam)
91{
92 RT_NOREF(pvParam);
93
94 /* Don't bother deregistering the stat samples as they get destroyed by STAM. */
95 RTMemFree(pCore);
96 return VINF_SUCCESS;
97}
98
99
100/**
101 * Destroy a heap.
102 *
103 * @param pHeap Heap handle.
104 */
105void mmR3HeapDestroy(PMMHEAP pHeap)
106{
107 /*
108 * Start by deleting the lock, that'll trap anyone
109 * attempting to use the heap.
110 */
111 RTCritSectDelete(&pHeap->Lock);
112
113 /*
114 * Walk the node list and free all the memory.
115 */
116 PMMHEAPHDR pHdr = pHeap->pHead;
117 while (pHdr)
118 {
119 void *pv = pHdr;
120 pHdr = pHdr->pNext;
121 RTMemFree(pv);
122 }
123
124 /*
125 * Free the stat nodes.
126 */
127 RTAvlULDestroy(&pHeap->pStatTree, mmR3HeapStatTreeDestroy, NULL);
128 RTMemFree(pHeap);
129}
130
131
132/**
133 * Allocate memory associating it with the VM for collective cleanup.
134 *
135 * The memory will be allocated from the default heap but a header
136 * is added in which we keep track of which VM it belongs to and chain
137 * all the allocations together so they can be freed in one go.
138 *
139 * This interface is typically used for memory block which will not be
140 * freed during the life of the VM.
141 *
142 * @returns Pointer to allocated memory.
143 * @param pUVM Pointer to the user mode VM structure.
144 * @param enmTag Statistics tag. Statistics are collected on a per tag
145 * basis in addition to a global one. Thus we can easily
146 * identify how memory is used by the VM. See MM_TAG_*.
147 * @param cbSize Size of the block.
148 */
149VMMR3DECL(void *) MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize)
150{
151 Assert(pUVM->mm.s.pHeap);
152 return mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, false);
153}
154
155
156/**
157 * Allocate memory associating it with the VM for collective cleanup.
158 *
159 * The memory will be allocated from the default heap but a header
160 * is added in which we keep track of which VM it belongs to and chain
161 * all the allocations together so they can be freed in one go.
162 *
163 * This interface is typically used for memory block which will not be
164 * freed during the life of the VM.
165 *
166 * @returns Pointer to allocated memory.
167 * @param pVM The cross context VM structure.
168 * @param enmTag Statistics tag. Statistics are collected on a per tag
169 * basis in addition to a global one. Thus we can easily
170 * identify how memory is used by the VM. See MM_TAG_*.
171 * @param cbSize Size of the block.
172 */
173VMMR3DECL(void *) MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize)
174{
175 return mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, false);
176}
177
178
179/**
180 * Same as MMR3HeapAllocU().
181 *
182 * @returns Pointer to allocated memory.
183 * @param pUVM Pointer to the user mode VM structure.
184 * @param enmTag Statistics tag. Statistics are collected on a per tag
185 * basis in addition to a global one. Thus we can easily
186 * identify how memory is used by the VM. See MM_TAG_*.
187 * @param cbSize Size of the block.
188 * @param ppv Where to store the pointer to the allocated memory on success.
189 */
190VMMR3DECL(int) MMR3HeapAllocExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv)
191{
192 Assert(pUVM->mm.s.pHeap);
193 void *pv = mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, false);
194 if (pv)
195 {
196 *ppv = pv;
197 return VINF_SUCCESS;
198 }
199 return VERR_NO_MEMORY;
200}
201
202
203/**
204 * Same as MMR3HeapAlloc().
205 *
206 * @returns Pointer to allocated memory.
207 * @param pVM The cross context VM structure.
208 * @param enmTag Statistics tag. Statistics are collected on a per tag
209 * basis in addition to a global one. Thus we can easily
210 * identify how memory is used by the VM. See MM_TAG_*.
211 * @param cbSize Size of the block.
212 * @param ppv Where to store the pointer to the allocated memory on success.
213 */
214VMMR3DECL(int) MMR3HeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv)
215{
216 void *pv = mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, false);
217 if (pv)
218 {
219 *ppv = pv;
220 return VINF_SUCCESS;
221 }
222 return VERR_NO_MEMORY;
223}
224
225
226/**
227 * Same as MMR3HeapAlloc() only the memory is zeroed.
228 *
229 * @returns Pointer to allocated memory.
230 * @param pUVM Pointer to the user mode VM structure.
231 * @param enmTag Statistics tag. Statistics are collected on a per tag
232 * basis in addition to a global one. Thus we can easily
233 * identify how memory is used by the VM. See MM_TAG_*.
234 * @param cbSize Size of the block.
235 */
236VMMR3DECL(void *) MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize)
237{
238 return mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, true);
239}
240
241
242/**
243 * Same as MMR3HeapAlloc() only the memory is zeroed.
244 *
245 * @returns Pointer to allocated memory.
246 * @param pVM The cross context VM structure.
247 * @param enmTag Statistics tag. Statistics are collected on a per tag
248 * basis in addition to a global one. Thus we can easily
249 * identify how memory is used by the VM. See MM_TAG_*.
250 * @param cbSize Size of the block.
251 */
252VMMR3DECL(void *) MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize)
253{
254 return mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, true);
255}
256
257
258/**
259 * Same as MMR3HeapAllocZ().
260 *
261 * @returns Pointer to allocated memory.
262 * @param pUVM Pointer to the user mode VM structure.
263 * @param enmTag Statistics tag. Statistics are collected on a per tag
264 * basis in addition to a global one. Thus we can easily
265 * identify how memory is used by the VM. See MM_TAG_*.
266 * @param cbSize Size of the block.
267 * @param ppv Where to store the pointer to the allocated memory on success.
268 */
269VMMR3DECL(int) MMR3HeapAllocZExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv)
270{
271 Assert(pUVM->mm.s.pHeap);
272 void *pv = mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, true);
273 if (pv)
274 {
275 *ppv = pv;
276 return VINF_SUCCESS;
277 }
278 return VERR_NO_MEMORY;
279}
280
281
282/**
283 * Same as MMR3HeapAllocZ().
284 *
285 * @returns Pointer to allocated memory.
286 * @param pVM The cross context VM structure.
287 * @param enmTag Statistics tag. Statistics are collected on a per tag
288 * basis in addition to a global one. Thus we can easily
289 * identify how memory is used by the VM. See MM_TAG_*.
290 * @param cbSize Size of the block.
291 * @param ppv Where to store the pointer to the allocated memory on success.
292 */
293VMMR3DECL(int) MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv)
294{
295 void *pv = mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, true);
296 if (pv)
297 {
298 *ppv = pv;
299 return VINF_SUCCESS;
300 }
301 return VERR_NO_MEMORY;
302}
303
304
305/**
306 * Links @a pHdr into the heap block list (tail).
307 *
308 * @param pHeap Heap handle.
309 * @param pHdr The block to link.
310 *
311 * @note Caller has locked the heap!
312 */
313DECLINLINE(void) mmR3HeapLink(PMMHEAP pHeap, PMMHEAPHDR pHdr)
314{
315 /* Tail insertion: */
316 pHdr->pNext = NULL;
317 PMMHEAPHDR pTail = pHeap->pTail;
318 pHdr->pPrev = pTail;
319 if (pTail)
320 {
321 Assert(!pTail->pNext);
322 pTail->pNext = pHdr;
323 }
324 else
325 {
326 Assert(!pHeap->pHead);
327 pHeap->pHead = pHdr;
328 }
329 pHeap->pTail = pHdr;
330}
331
332
333/**
334 * Unlinks @a pHdr from the heal block list.
335 *
336 * @param pHeap Heap handle.
337 * @param pHdr The block to unlink.
338 *
339 * @note Caller has locked the heap!
340 */
341DECLINLINE(void) mmR3HeapUnlink(PMMHEAP pHeap, PMMHEAPHDR pHdr)
342{
343 PMMHEAPHDR const pPrev = pHdr->pPrev;
344 PMMHEAPHDR const pNext = pHdr->pNext;
345 if (pPrev)
346 pPrev->pNext = pNext;
347 else
348 pHeap->pHead = pNext;
349
350 if (pNext)
351 pNext->pPrev = pPrev;
352 else
353 pHeap->pTail = pHdr->pPrev;
354}
355
356
357/**
358 * Allocate memory from the heap.
359 *
360 * @returns Pointer to allocated memory.
361 * @param pHeap Heap handle.
362 * @param enmTag Statistics tag. Statistics are collected on a per tag
363 * basis in addition to a global one. Thus we can easily
364 * identify how memory is used by the VM. See MM_TAG_*.
365 * @param cbSize Size of the block.
366 * @param fZero Whether or not to zero the memory block.
367 */
368void *mmR3HeapAlloc(PMMHEAP pHeap, MMTAG enmTag, size_t cbSize, bool fZero)
369{
370#ifdef MMR3HEAP_WITH_STATISTICS
371 RTCritSectEnter(&pHeap->Lock);
372
373 /*
374 * Find/alloc statistics nodes.
375 */
376 pHeap->Stat.cAllocations++;
377 PMMHEAPSTAT pStat = (PMMHEAPSTAT)RTAvlULGet(&pHeap->pStatTree, (AVLULKEY)enmTag);
378 if (pStat)
379 {
380 pStat->cAllocations++;
381
382 RTCritSectLeave(&pHeap->Lock);
383 }
384 else
385 {
386 pStat = (PMMHEAPSTAT)RTMemAllocZ(sizeof(MMHEAPSTAT));
387 if (!pStat)
388 {
389 pHeap->Stat.cFailures++;
390 AssertMsgFailed(("Failed to allocate heap stat record.\n"));
391 RTCritSectLeave(&pHeap->Lock);
392 return NULL;
393 }
394 pStat->Core.Key = (AVLULKEY)enmTag;
395 pStat->pHeap = pHeap;
396 RTAvlULInsert(&pHeap->pStatTree, &pStat->Core);
397
398 pStat->cAllocations++;
399 RTCritSectLeave(&pHeap->Lock);
400
401 /* register the statistics */
402 PUVM pUVM = pHeap->pUVM;
403 const char *pszTag = mmGetTagName(enmTag);
404 STAMR3RegisterFU(pUVM, &pStat->cbCurAllocated, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes currently allocated.", "/MM/R3Heap/%s", pszTag);
405 STAMR3RegisterFU(pUVM, &pStat->cAllocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number or MMR3HeapAlloc() calls.", "/MM/R3Heap/%s/cAllocations", pszTag);
406 STAMR3RegisterFU(pUVM, &pStat->cReallocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number of MMR3HeapRealloc() calls.", "/MM/R3Heap/%s/cReallocations", pszTag);
407 STAMR3RegisterFU(pUVM, &pStat->cFrees, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number of MMR3HeapFree() calls.", "/MM/R3Heap/%s/cFrees", pszTag);
408 STAMR3RegisterFU(pUVM, &pStat->cFailures, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failures.", "/MM/R3Heap/%s/cFailures", pszTag);
409 STAMR3RegisterFU(pUVM, &pStat->cbAllocated, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total number of bytes allocated.", "/MM/R3Heap/%s/cbAllocated", pszTag);
410 STAMR3RegisterFU(pUVM, &pStat->cbFreed, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total number of bytes freed.", "/MM/R3Heap/%s/cbFreed", pszTag);
411 }
412#else
413 RT_NOREF_PV(enmTag);
414#endif
415
416 /*
417 * Validate input.
418 */
419 if (cbSize == 0)
420 {
421#ifdef MMR3HEAP_WITH_STATISTICS
422 RTCritSectEnter(&pHeap->Lock);
423 pStat->cFailures++;
424 pHeap->Stat.cFailures++;
425 RTCritSectLeave(&pHeap->Lock);
426#endif
427 AssertFailed();
428 return NULL;
429 }
430
431 /*
432 * Allocate heap block.
433 */
434 cbSize = RT_ALIGN_Z(cbSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
435 PMMHEAPHDR const pHdr = (PMMHEAPHDR)(fZero ? RTMemAllocZ(cbSize) : RTMemAlloc(cbSize));
436 if (pHdr)
437 { /* likely */ }
438 else
439 {
440 AssertMsgFailed(("Failed to allocate heap block %d, enmTag=%x(%.4s).\n", cbSize, enmTag, &enmTag));
441#ifdef MMR3HEAP_WITH_STATISTICS
442 RTCritSectEnter(&pHeap->Lock);
443 pStat->cFailures++;
444 pHeap->Stat.cFailures++;
445 RTCritSectLeave(&pHeap->Lock);
446#endif
447 return NULL;
448 }
449 Assert(!((uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1)));
450
451 /*
452 * Init and link in the header.
453 */
454#ifdef MMR3HEAP_WITH_STATISTICS
455 pHdr->pStat = pStat;
456#else
457 pHdr->pStat = &pHeap->Stat;
458#endif
459 pHdr->cbSize = cbSize;
460
461 RTCritSectEnter(&pHeap->Lock);
462
463 mmR3HeapLink(pHeap, pHdr);
464
465 /*
466 * Update statistics
467 */
468#ifdef MMR3HEAP_WITH_STATISTICS
469 pStat->cbAllocated += cbSize;
470 pStat->cbCurAllocated += cbSize;
471 pHeap->Stat.cbAllocated += cbSize;
472 pHeap->Stat.cbCurAllocated += cbSize;
473#endif
474
475 RTCritSectLeave(&pHeap->Lock);
476
477 return pHdr + 1;
478}
479
480
481/**
482 * Reallocate memory allocated with MMR3HeapAlloc(), MMR3HeapAllocZ() or
483 * MMR3HeapRealloc().
484 *
485 * Any additional memory is zeroed (only reliable if the initial allocation was
486 * also of the zeroing kind).
487 *
488 * @returns Pointer to reallocated memory.
489 * @param pv Pointer to the memory block to reallocate.
490 * Must not be NULL!
491 * @param cbNewSize New block size.
492 */
493VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize)
494{
495 AssertMsg(pv, ("Invalid pointer pv=%p\n", pv));
496 if (!pv)
497 return NULL;
498
499 /*
500 * If newsize is zero then this is a free.
501 */
502 if (!cbNewSize)
503 {
504 MMR3HeapFree(pv);
505 return NULL;
506 }
507
508 /*
509 * Validate header.
510 */
511 PMMHEAPHDR const pHdr = (PMMHEAPHDR)pv - 1;
512 size_t const cbOldSize = pHdr->cbSize;
513 AssertMsgReturn( !(cbOldSize & (MMR3HEAP_SIZE_ALIGNMENT - 1))
514 && !((uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1)),
515 ("Invalid heap header! pv=%p, size=%#x\n", pv, cbOldSize),
516 NULL);
517 Assert(pHdr->pStat != NULL);
518 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
519 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
520
521 PMMHEAP pHeap = pHdr->pStat->pHeap;
522
523 /*
524 * Unlink the header before we reallocate the block.
525 */
526 RTCritSectEnter(&pHeap->Lock);
527#ifdef MMR3HEAP_WITH_STATISTICS
528 pHdr->pStat->cReallocations++;
529 pHeap->Stat.cReallocations++;
530#endif
531 mmR3HeapUnlink(pHeap, pHdr);
532 RTCritSectLeave(&pHeap->Lock);
533
534 /*
535 * Reallocate the block. Clear added space.
536 */
537 cbNewSize = RT_ALIGN_Z(cbNewSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
538 PMMHEAPHDR pHdrNew = (PMMHEAPHDR)RTMemReallocZ(pHdr, cbOldSize, cbNewSize);
539 if (pHdrNew)
540 pHdrNew->cbSize = cbNewSize;
541 else
542 {
543 RTCritSectEnter(&pHeap->Lock);
544 mmR3HeapLink(pHeap, pHdr);
545#ifdef MMR3HEAP_WITH_STATISTICS
546 pHdr->pStat->cFailures++;
547 pHeap->Stat.cFailures++;
548#endif
549 RTCritSectLeave(&pHeap->Lock);
550 return NULL;
551 }
552
553 RTCritSectEnter(&pHeap->Lock);
554
555 /*
556 * Relink the header.
557 */
558 mmR3HeapLink(pHeap, pHdrNew);
559
560 /*
561 * Update statistics.
562 */
563#ifdef MMR3HEAP_WITH_STATISTICS
564 pHdrNew->pStat->cbAllocated += cbNewSize - pHdrNew->cbSize;
565 pHeap->Stat.cbAllocated += cbNewSize - pHdrNew->cbSize;
566#endif
567
568 RTCritSectLeave(&pHeap->Lock);
569
570 return pHdrNew + 1;
571}
572
573
574/**
575 * Duplicates the specified string.
576 *
577 * @returns Pointer to the duplicate.
578 * @returns NULL on failure or when input NULL.
579 * @param pUVM Pointer to the user mode VM structure.
580 * @param enmTag Statistics tag. Statistics are collected on a per tag
581 * basis in addition to a global one. Thus we can easily
582 * identify how memory is used by the VM. See MM_TAG_*.
583 * @param psz The string to duplicate. NULL is allowed.
584 */
585VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz)
586{
587 if (!psz)
588 return NULL;
589 AssertPtr(psz);
590
591 size_t cch = strlen(psz) + 1;
592 char *pszDup = (char *)MMR3HeapAllocU(pUVM, enmTag, cch);
593 if (pszDup)
594 memcpy(pszDup, psz, cch);
595 return pszDup;
596}
597
598
599/**
600 * Duplicates the specified string.
601 *
602 * @returns Pointer to the duplicate.
603 * @returns NULL on failure or when input NULL.
604 * @param pVM The cross context VM structure.
605 * @param enmTag Statistics tag. Statistics are collected on a per tag
606 * basis in addition to a global one. Thus we can easily
607 * identify how memory is used by the VM. See MM_TAG_*.
608 * @param psz The string to duplicate. NULL is allowed.
609 */
610VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz)
611{
612 return MMR3HeapStrDupU(pVM->pUVM, enmTag, psz);
613}
614
615
616/**
617 * Allocating string printf.
618 *
619 * @returns Pointer to the string.
620 * @param pVM The cross context VM structure.
621 * @param enmTag The statistics tag.
622 * @param pszFormat The format string.
623 * @param ... Format arguments.
624 */
625VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...)
626{
627 va_list va;
628 va_start(va, pszFormat);
629 char *psz = MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
630 va_end(va);
631 return psz;
632}
633
634
635/**
636 * Allocating string printf.
637 *
638 * @returns Pointer to the string.
639 * @param pUVM Pointer to the user mode VM structure.
640 * @param enmTag The statistics tag.
641 * @param pszFormat The format string.
642 * @param ... Format arguments.
643 */
644VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...)
645{
646 va_list va;
647 va_start(va, pszFormat);
648 char *psz = MMR3HeapAPrintfVU(pUVM, enmTag, pszFormat, va);
649 va_end(va);
650 return psz;
651}
652
653
654/**
655 * Allocating string printf.
656 *
657 * @returns Pointer to the string.
658 * @param pVM The cross context VM structure.
659 * @param enmTag The statistics tag.
660 * @param pszFormat The format string.
661 * @param va Format arguments.
662 */
663VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va)
664{
665 return MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
666}
667
668
669/**
670 * Allocating string printf.
671 *
672 * @returns Pointer to the string.
673 * @param pUVM Pointer to the user mode VM structure.
674 * @param enmTag The statistics tag.
675 * @param pszFormat The format string.
676 * @param va Format arguments.
677 */
678VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va)
679{
680 /*
681 * The lazy bird way.
682 */
683 char *psz;
684 int cch = RTStrAPrintfV(&psz, pszFormat, va);
685 if (cch < 0)
686 return NULL;
687 Assert(psz[cch] == '\0');
688 char *pszRet = (char *)MMR3HeapAllocU(pUVM, enmTag, cch + 1);
689 if (pszRet)
690 memcpy(pszRet, psz, cch + 1);
691 RTStrFree(psz);
692 return pszRet;
693}
694
695
696/**
697 * Releases memory allocated with MMR3HeapAlloc() or MMR3HeapRealloc().
698 *
699 * The memory is cleared/filled before freeing to prevent heap spraying, info
700 * leaks, and help detect use after free trouble.
701 *
702 * @param pv Pointer to the memory block to free.
703 */
704VMMR3DECL(void) MMR3HeapFree(void *pv)
705{
706 /* Ignore NULL pointers. */
707 if (!pv)
708 return;
709
710 /*
711 * Validate header.
712 */
713 PMMHEAPHDR const pHdr = (PMMHEAPHDR)pv - 1;
714 size_t const cbAllocation = pHdr->cbSize;
715 AssertMsgReturnVoid( !(pHdr->cbSize & (MMR3HEAP_SIZE_ALIGNMENT - 1))
716 && !((uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1)),
717 ("Invalid heap header! pv=%p, size=%#x\n", pv, pHdr->cbSize));
718 AssertPtr(pHdr->pStat);
719 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
720 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
721
722 /*
723 * Update statistics
724 */
725 PMMHEAP pHeap = pHdr->pStat->pHeap;
726 RTCritSectEnter(&pHeap->Lock);
727
728#ifdef MMR3HEAP_WITH_STATISTICS
729 pHdr->pStat->cFrees++;
730 pHeap->Stat.cFrees++;
731 pHdr->pStat->cbFreed += cbAllocation;
732 pHeap->Stat.cbFreed += cbAllocation;
733 pHdr->pStat->cbCurAllocated -= cbAllocation;
734 pHeap->Stat.cbCurAllocated -= cbAllocation;
735#endif
736
737 /*
738 * Unlink it.
739 */
740 mmR3HeapUnlink(pHeap, pHdr);
741
742 RTCritSectLeave(&pHeap->Lock);
743
744 /*
745 * Free the memory. We clear just to be on the safe size wrt
746 * heap spraying and leaking sensitive info (also helps detecting
747 * double freeing).
748 */
749 RTMemFreeZ(pHdr, cbAllocation);
750}
751
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use