VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/memsafer-r3.cpp@ 78335

Last change on this file since 78335 was 78335, checked in by vboxsync, 6 years ago

IPRT/mem: Use RTMEMPAGEALLOC_F_ADVISE_LOCKED & RTMEMPAGEALLOC_F_ADVISE_NO_DUMP when allocating safer memory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.4 KB
Line 
1/* $Id: memsafer-r3.cpp 78335 2019-04-26 19:54:48Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocate for Sensitive Data, generic heap-based implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 * 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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/memsafer.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/critsect.h>
38#include <iprt/err.h>
39#include <iprt/mem.h>
40#include <iprt/once.h>
41#include <iprt/rand.h>
42#include <iprt/param.h>
43#include <iprt/string.h>
44#ifdef IN_SUP_R3
45# include <VBox/sup.h>
46#endif
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** Allocation size alignment (power of two). */
53#define RTMEMSAFER_ALIGN 16
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/**
60 * Allocators.
61 */
62typedef enum RTMEMSAFERALLOCATOR
63{
64 /** Invalid method. */
65 RTMEMSAFERALLOCATOR_INVALID = 0,
66 /** RTMemPageAlloc. */
67 RTMEMSAFERALLOCATOR_RTMEMPAGE,
68 /** SUPR3PageAllocEx. */
69 RTMEMSAFERALLOCATOR_SUPR3
70} RTMEMSAFERALLOCATOR;
71
72/**
73 * Tracking node (lives on normal heap).
74 */
75typedef struct RTMEMSAFERNODE
76{
77 /** Node core.
78 * The core key is a scrambled pointer the user memory. */
79 AVLPVNODECORE Core;
80 /** The allocation flags. */
81 uint32_t fFlags;
82 /** The offset into the allocation of the user memory. */
83 uint32_t offUser;
84 /** The requested allocation size. */
85 size_t cbUser;
86 /** The allocation size in pages, this includes the two guard pages. */
87 uint32_t cPages;
88 /** The allocator used for this node. */
89 RTMEMSAFERALLOCATOR enmAllocator;
90 /** XOR scrambler value for memory. */
91 uintptr_t uScramblerXor;
92} RTMEMSAFERNODE;
93/** Pointer to an allocation tracking node. */
94typedef RTMEMSAFERNODE *PRTMEMSAFERNODE;
95
96
97/*********************************************************************************************************************************
98* Global Variables *
99*********************************************************************************************************************************/
100/** Init once structure for this module. */
101static RTONCE g_MemSaferOnce = RTONCE_INITIALIZER;
102/** Critical section protecting the allocation tree. */
103static RTCRITSECTRW g_MemSaferCritSect;
104/** Tree of allocation nodes. */
105static AVLPVTREE g_pMemSaferTree;
106/** XOR scrambler value pointers. */
107static uintptr_t g_uMemSaferPtrScramblerXor;
108/** Pointer rotate shift count.*/
109static uintptr_t g_cMemSaferPtrScramblerRotate;
110
111
112/**
113 * @callback_method_impl{FNRTONCE, Inits globals.}
114 */
115static DECLCALLBACK(int32_t) rtMemSaferOnceInit(void *pvUserIgnore)
116{
117 RT_NOREF_PV(pvUserIgnore);
118
119 g_uMemSaferPtrScramblerXor = (uintptr_t)RTRandU64();
120 g_cMemSaferPtrScramblerRotate = RTRandU32Ex(0, ARCH_BITS - 1);
121 return RTCritSectRwInit(&g_MemSaferCritSect);
122}
123
124
125/**
126 * @callback_method_impl{PFNRTONCECLEANUP, Cleans up globals.}
127 */
128static DECLCALLBACK(void) rtMemSaferOnceTerm(void *pvUser, bool fLazyCleanUpOk)
129{
130 RT_NOREF_PV(pvUser);
131
132 if (!fLazyCleanUpOk)
133 {
134 RTCritSectRwDelete(&g_MemSaferCritSect);
135 Assert(!g_pMemSaferTree);
136 }
137}
138
139
140
141DECLINLINE(void *) rtMemSaferScramblePointer(void *pvUser)
142{
143 uintptr_t uPtr = (uintptr_t)pvUser;
144 uPtr ^= g_uMemSaferPtrScramblerXor;
145#if ARCH_BITS == 64
146 uPtr = ASMRotateRightU64(uPtr, g_cMemSaferPtrScramblerRotate);
147#elif ARCH_BITS == 32
148 uPtr = ASMRotateRightU32(uPtr, g_cMemSaferPtrScramblerRotate);
149#else
150# error "Unsupported/missing ARCH_BITS."
151#endif
152 return (void *)uPtr;
153}
154
155
156/**
157 * Inserts a tracking node into the tree.
158 *
159 * @param pThis The allocation tracking node to insert.
160 */
161static void rtMemSaferNodeInsert(PRTMEMSAFERNODE pThis)
162{
163 RTCritSectRwEnterExcl(&g_MemSaferCritSect);
164 pThis->Core.Key = rtMemSaferScramblePointer(pThis->Core.Key);
165 bool fRc = RTAvlPVInsert(&g_pMemSaferTree, &pThis->Core);
166 RTCritSectRwLeaveExcl(&g_MemSaferCritSect);
167 Assert(fRc); NOREF(fRc);
168}
169
170
171/**
172 * Finds a tracking node into the tree.
173 *
174 * @returns The allocation tracking node for @a pvUser. NULL if not found.
175 * @param pvUser The user pointer to the allocation.
176 */
177static PRTMEMSAFERNODE rtMemSaferNodeLookup(void *pvUser)
178{
179 void *pvKey = rtMemSaferScramblePointer(pvUser);
180 RTCritSectRwEnterShared(&g_MemSaferCritSect);
181 PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTAvlPVGet(&g_pMemSaferTree, pvKey);
182 RTCritSectRwLeaveShared(&g_MemSaferCritSect);
183 return pThis;
184}
185
186
187/**
188 * Removes a tracking node from the tree.
189 *
190 * @returns The allocation tracking node for @a pvUser. NULL if not found.
191 * @param pvUser The user pointer to the allocation.
192 */
193static PRTMEMSAFERNODE rtMemSaferNodeRemove(void *pvUser)
194{
195 void *pvKey = rtMemSaferScramblePointer(pvUser);
196 RTCritSectRwEnterExcl(&g_MemSaferCritSect);
197 PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTAvlPVRemove(&g_pMemSaferTree, pvKey);
198 RTCritSectRwLeaveExcl(&g_MemSaferCritSect);
199 return pThis;
200}
201
202
203RTDECL(int) RTMemSaferScramble(void *pv, size_t cb)
204{
205 PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pv);
206 AssertReturn(pThis, VERR_INVALID_POINTER);
207 AssertMsgReturn(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser), VERR_INVALID_PARAMETER);
208
209 /* First time we get a new xor value. */
210 if (!pThis->uScramblerXor)
211 pThis->uScramblerXor = (uintptr_t)RTRandU64();
212
213 /* Note! This isn't supposed to be safe, just less obvious. */
214 uintptr_t *pu = (uintptr_t *)pv;
215 cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
216 while (cb > 0)
217 {
218 *pu ^= pThis->uScramblerXor;
219 pu++;
220 cb -= sizeof(*pu);
221 }
222
223 return VINF_SUCCESS;
224}
225RT_EXPORT_SYMBOL(RTMemSaferScramble);
226
227
228RTDECL(int) RTMemSaferUnscramble(void *pv, size_t cb)
229{
230 PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pv);
231 AssertReturn(pThis, VERR_INVALID_POINTER);
232 AssertMsgReturn(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser), VERR_INVALID_PARAMETER);
233
234 /* Note! This isn't supposed to be safe, just less obvious. */
235 uintptr_t *pu = (uintptr_t *)pv;
236 cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
237 while (cb > 0)
238 {
239 *pu ^= pThis->uScramblerXor;
240 pu++;
241 cb -= sizeof(*pu);
242 }
243
244 return VINF_SUCCESS;
245}
246RT_EXPORT_SYMBOL(RTMemSaferUnscramble);
247
248
249/**
250 * Initializes the pages.
251 *
252 * Fills the memory with random bytes in order to make it less obvious where the
253 * secret data starts and ends. We also zero the user memory in case the
254 * allocator does not do this.
255 *
256 * @param pThis The allocation tracer node. The Core.Key member
257 * will be set.
258 * @param pvPages The pages to initialize.
259 */
260static void rtMemSaferInitializePages(PRTMEMSAFERNODE pThis, void *pvPages)
261{
262 RTRandBytes(pvPages, PAGE_SIZE + pThis->offUser);
263
264 uint8_t *pbUser = (uint8_t *)pvPages + PAGE_SIZE + pThis->offUser;
265 pThis->Core.Key = pbUser;
266 RT_BZERO(pbUser, pThis->cbUser); /* paranoia */
267
268 RTRandBytes(pbUser + pThis->cbUser, (size_t)pThis->cPages * PAGE_SIZE - PAGE_SIZE - pThis->offUser - pThis->cbUser);
269}
270
271
272/**
273 * Allocates and initializes pages from the support driver and initializes it.
274 *
275 * @returns VBox status code.
276 * @param pThis The allocator node. Core.Key will be set on successful
277 * return (unscrambled).
278 */
279static int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
280{
281#ifdef IN_SUP_R3
282 /*
283 * Try allocate the memory.
284 */
285 void *pvPages;
286 int rc = SUPR3PageAllocEx(pThis->cPages, 0 /* fFlags */, &pvPages, NULL /* pR0Ptr */, NULL /* paPages */);
287 if (RT_SUCCESS(rc))
288 {
289 rtMemSaferInitializePages(pThis, pvPages);
290
291 /*
292 * On darwin we cannot allocate pages without an R0 mapping and
293 * SUPR3PageAllocEx falls back to another method which is incompatible with
294 * the way SUPR3PageProtect works. Ignore changing the protection of the guard
295 * pages.
296 */
297#ifdef RT_OS_DARWIN
298 return VINF_SUCCESS;
299#else
300 /*
301 * Configure the guard pages.
302 * SUPR3PageProtect isn't supported on all hosts, we ignore that.
303 */
304 rc = SUPR3PageProtect(pvPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_NONE);
305 if (RT_SUCCESS(rc))
306 {
307 rc = SUPR3PageProtect(pvPages, NIL_RTR0PTR, (pThis->cPages - 1) * PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
308 if (RT_SUCCESS(rc))
309 return VINF_SUCCESS;
310 SUPR3PageProtect(pvPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
311 }
312 else if (rc == VERR_NOT_SUPPORTED)
313 return VINF_SUCCESS;
314
315 /* failed. */
316 int rc2 = SUPR3PageFreeEx(pvPages, pThis->cPages); AssertRC(rc2);
317#endif
318 }
319 return rc;
320
321#else /* !IN_SUP_R3 */
322 RT_NOREF_PV(pThis);
323 return VERR_NOT_SUPPORTED;
324#endif /* !IN_SUP_R3 */
325}
326
327
328/**
329 * Allocates and initializes pages using the IPRT page allocator API.
330 *
331 * @returns VBox status code.
332 * @param pThis The allocator node. Core.Key will be set on successful
333 * return (unscrambled).
334 */
335static int rtMemSaferMemAllocPages(PRTMEMSAFERNODE pThis)
336{
337 /*
338 * Try allocate the memory.
339 */
340 int rc = VINF_SUCCESS;
341 void *pvPages = RTMemPageAllocEx((size_t)pThis->cPages * PAGE_SIZE,
342 RTMEMPAGEALLOC_F_ADVISE_LOCKED | RTMEMPAGEALLOC_F_ADVISE_NO_DUMP | RTMEMPAGEALLOC_F_ZERO);
343 if (pvPages)
344 {
345 rtMemSaferInitializePages(pThis, pvPages);
346
347 /*
348 * Configure the guard pages.
349 */
350 rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_NONE);
351 if (RT_SUCCESS(rc))
352 {
353 rc = RTMemProtect((uint8_t *)pvPages + (size_t)(pThis->cPages - 1U) * PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
354 if (RT_SUCCESS(rc))
355 return VINF_SUCCESS;
356 rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
357 }
358
359 /* failed. */
360 RTMemPageFree(pvPages, (size_t)pThis->cPages * PAGE_SIZE);
361 }
362 else
363 rc = VERR_NO_PAGE_MEMORY;
364
365 return rc;
366}
367
368
369RTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_DEF
370{
371 RT_NOREF_PV(pszTag);
372
373 /*
374 * Validate input.
375 */
376 AssertPtrReturn(ppvNew, VERR_INVALID_PARAMETER);
377 *ppvNew = NULL;
378 AssertReturn(cb, VERR_INVALID_PARAMETER);
379 AssertReturn(cb <= 32U*_1M - PAGE_SIZE * 3U, VERR_ALLOCATION_TOO_BIG); /* Max 32 MB minus padding and guard pages. */
380 AssertReturn(!(fFlags & ~RTMEMSAFER_F_VALID_MASK), VERR_INVALID_FLAGS);
381
382 /*
383 * Initialize globals.
384 */
385 int rc = RTOnceEx(&g_MemSaferOnce, rtMemSaferOnceInit, rtMemSaferOnceTerm, NULL);
386 if (RT_SUCCESS(rc))
387 {
388 /*
389 * Allocate a tracker node first.
390 */
391 PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTMemAllocZ(sizeof(RTMEMSAFERNODE));
392 if (pThis)
393 {
394 /*
395 * Prepare the allocation.
396 */
397 pThis->cbUser = cb;
398 pThis->offUser = (RTRandU32Ex(0, 128) * RTMEMSAFER_ALIGN) & PAGE_OFFSET_MASK;
399
400 size_t cbNeeded = pThis->offUser + pThis->cbUser;
401 cbNeeded = RT_ALIGN_Z(cbNeeded, PAGE_SIZE);
402
403 pThis->cPages = (uint32_t)(cbNeeded / PAGE_SIZE) + 2; /* +2 for guard pages */
404
405 /*
406 * Try allocate the memory, using the best allocator by default and
407 * falling back on the less safe one.
408 */
409 rc = rtMemSaferSupR3AllocPages(pThis);
410 if (RT_SUCCESS(rc))
411 pThis->enmAllocator = RTMEMSAFERALLOCATOR_SUPR3;
412 else if (!(fFlags & RTMEMSAFER_F_REQUIRE_NOT_PAGABLE))
413 {
414 rc = rtMemSaferMemAllocPages(pThis);
415 if (RT_SUCCESS(rc))
416 pThis->enmAllocator = RTMEMSAFERALLOCATOR_RTMEMPAGE;
417 }
418 if (RT_SUCCESS(rc))
419 {
420 /*
421 * Insert the node.
422 */
423 *ppvNew = pThis->Core.Key;
424 rtMemSaferNodeInsert(pThis); /* (Scrambles Core.Key) */
425 return VINF_SUCCESS;
426 }
427
428 RTMemFree(pThis);
429 }
430 else
431 rc = VERR_NO_MEMORY;
432 }
433 return rc;
434}
435RT_EXPORT_SYMBOL(RTMemSaferAllocZExTag);
436
437
438RTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW_DEF
439{
440 if (pv)
441 {
442 PRTMEMSAFERNODE pThis = rtMemSaferNodeRemove(pv);
443 AssertReturnVoid(pThis);
444 AssertMsg(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser));
445
446 /*
447 * Wipe the user memory first.
448 */
449 RTMemWipeThoroughly(pv, RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN), 3);
450
451 /*
452 * Free the pages.
453 */
454 uint8_t *pbPages = (uint8_t *)pv - pThis->offUser - PAGE_SIZE;
455 size_t cbPages = (size_t)pThis->cPages * PAGE_SIZE;
456 switch (pThis->enmAllocator)
457 {
458#ifdef IN_SUP_R3
459 case RTMEMSAFERALLOCATOR_SUPR3:
460 SUPR3PageProtect(pbPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
461 SUPR3PageProtect(pbPages, NIL_RTR0PTR, (uint32_t)(cbPages - PAGE_SIZE), PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
462 SUPR3PageFreeEx(pbPages, pThis->cPages);
463 break;
464#endif
465 case RTMEMSAFERALLOCATOR_RTMEMPAGE:
466 RTMemProtect(pbPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
467 RTMemProtect(pbPages + cbPages - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
468 RTMemPageFree(pbPages, cbPages);
469 break;
470
471 default:
472 AssertFailed();
473 }
474
475 /*
476 * Free the tracking node.
477 */
478 pThis->Core.Key = NULL;
479 pThis->offUser = 0;
480 pThis->cbUser = 0;
481 RTMemFree(pThis);
482 }
483 else
484 Assert(cb == 0);
485}
486RT_EXPORT_SYMBOL(RTMemSaferFree);
487
488
489/**
490 * The simplest reallocation method: allocate new block, copy over the data,
491 * free old block.
492 */
493static int rtMemSaferReallocSimpler(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag)
494{
495 void *pvNew;
496 int rc = RTMemSaferAllocZExTag(&pvNew, cbNew, fFlags, pszTag);
497 if (RT_SUCCESS(rc))
498 {
499 memcpy(pvNew, pvOld, RT_MIN(cbNew, cbOld));
500 RTMemSaferFree(pvOld, cbOld);
501 *ppvNew = pvNew;
502 }
503 return rc;
504}
505
506
507RTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW_DEF
508{
509 int rc;
510 /* Real realloc. */
511 if (cbNew && cbOld)
512 {
513 PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pvOld);
514 AssertReturn(pThis, VERR_INVALID_POINTER);
515 AssertMsgStmt(cbOld == pThis->cbUser, ("cbOld=%#zx != %#zx\n", cbOld, pThis->cbUser), cbOld = pThis->cbUser);
516
517 if (pThis->fFlags == fFlags)
518 {
519 if (cbNew > cbOld)
520 {
521 /*
522 * Is the enough room for us to grow?
523 */
524 size_t cbMax = (size_t)(pThis->cPages - 2) * PAGE_SIZE;
525 if (cbNew <= cbMax)
526 {
527 size_t const cbAdded = (cbNew - cbOld);
528 size_t const cbAfter = cbMax - pThis->offUser - cbOld;
529 if (cbAfter >= cbAdded)
530 {
531 /*
532 * Sufficient space after the current allocation.
533 */
534 uint8_t *pbNewSpace = (uint8_t *)pvOld + cbOld;
535 RT_BZERO(pbNewSpace, cbAdded);
536 *ppvNew = pvOld;
537 }
538 else
539 {
540 /*
541 * Have to move the allocation to make enough room at the
542 * end. In order to make it a little less predictable and
543 * maybe avoid a relocation or two in the next call, divide
544 * the page offset by four until it it fits.
545 */
546 AssertReturn(rtMemSaferNodeRemove(pvOld) == pThis, VERR_INTERNAL_ERROR_3);
547 uint32_t offNewUser = pThis->offUser;
548 do
549 offNewUser = offNewUser / 2;
550 while ((pThis->offUser - offNewUser) + cbAfter < cbAdded);
551 offNewUser &= ~(RTMEMSAFER_ALIGN - 1U);
552
553 uint32_t const cbMove = pThis->offUser - offNewUser;
554 uint8_t *pbNew = (uint8_t *)pvOld - cbMove;
555 memmove(pbNew, pvOld, cbOld);
556
557 RT_BZERO(pbNew + cbOld, cbAdded);
558 if (cbMove > cbAdded)
559 RTMemWipeThoroughly(pbNew + cbNew, cbMove - cbAdded, 3);
560
561 pThis->offUser = offNewUser;
562 pThis->Core.Key = pbNew;
563 *ppvNew = pbNew;
564
565 rtMemSaferNodeInsert(pThis);
566 }
567 Assert(((uintptr_t)*ppvNew & PAGE_OFFSET_MASK) == pThis->offUser);
568 pThis->cbUser = cbNew;
569 rc = VINF_SUCCESS;
570 }
571 else
572 {
573 /*
574 * Not enough space, allocate a new block and copy over the data.
575 */
576 rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
577 }
578 }
579 else
580 {
581 /*
582 * Shrinking the allocation, just wipe the memory that is no longer
583 * being used.
584 */
585 if (cbNew != cbOld)
586 {
587 uint8_t *pbAbandond = (uint8_t *)pvOld + cbNew;
588 RTMemWipeThoroughly(pbAbandond, cbOld - cbNew, 3);
589 }
590 pThis->cbUser = cbNew;
591 *ppvNew = pvOld;
592 rc = VINF_SUCCESS;
593 }
594 }
595 else if (!pThis->fFlags)
596 {
597 /*
598 * New flags added. Allocate a new block and copy over the old one.
599 */
600 rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
601 }
602 else
603 {
604 /* Compatible flags. */
605 AssertMsgFailed(("fFlags=%#x old=%#x\n", fFlags, pThis->fFlags));
606 rc = VERR_INVALID_FLAGS;
607 }
608 }
609 /*
610 * First allocation. Pass it on.
611 */
612 else if (!cbOld)
613 {
614 Assert(pvOld == NULL);
615 rc = RTMemSaferAllocZExTag(ppvNew, cbNew, fFlags, pszTag);
616 }
617 /*
618 * Free operation. Pass it on.
619 */
620 else
621 {
622 RTMemSaferFree(pvOld, cbOld);
623 *ppvNew = NULL;
624 rc = VINF_SUCCESS;
625 }
626 return rc;
627}
628RT_EXPORT_SYMBOL(RTMemSaferReallocZExTag);
629
630
631RTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
632{
633 void *pvNew = NULL;
634 int rc = RTMemSaferAllocZExTag(&pvNew, cb, 0 /*fFlags*/, pszTag);
635 if (RT_SUCCESS(rc))
636 return pvNew;
637 return NULL;
638}
639RT_EXPORT_SYMBOL(RTMemSaferAllocZTag);
640
641
642RTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
643{
644 void *pvNew = NULL;
645 int rc = RTMemSaferReallocZExTag(cbOld, pvOld, cbNew, &pvNew, 0 /*fFlags*/, pszTag);
646 if (RT_SUCCESS(rc))
647 return pvNew;
648 return NULL;
649}
650RT_EXPORT_SYMBOL(RTMemSaferReallocZTag);
651
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