VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1/* $Id: memsafer-r3.cpp 76553 2019-01-01 01:45:53Z 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 = RTMemPageAlloc((size_t)pThis->cPages * PAGE_SIZE);
342 if (pvPages)
343 {
344 rtMemSaferInitializePages(pThis, pvPages);
345
346 /*
347 * Configure the guard pages.
348 */
349 rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_NONE);
350 if (RT_SUCCESS(rc))
351 {
352 rc = RTMemProtect((uint8_t *)pvPages + (size_t)(pThis->cPages - 1U) * PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
353 if (RT_SUCCESS(rc))
354 return VINF_SUCCESS;
355 rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
356 }
357
358 /* failed. */
359 RTMemPageFree(pvPages, (size_t)pThis->cPages * PAGE_SIZE);
360 }
361 else
362 rc = VERR_NO_PAGE_MEMORY;
363
364 return rc;
365}
366
367
368RTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW_DEF
369{
370 RT_NOREF_PV(pszTag);
371
372 /*
373 * Validate input.
374 */
375 AssertPtrReturn(ppvNew, VERR_INVALID_PARAMETER);
376 *ppvNew = NULL;
377 AssertReturn(cb, VERR_INVALID_PARAMETER);
378 AssertReturn(cb <= 32U*_1M - PAGE_SIZE * 3U, VERR_ALLOCATION_TOO_BIG); /* Max 32 MB minus padding and guard pages. */
379 AssertReturn(!(fFlags & ~RTMEMSAFER_F_VALID_MASK), VERR_INVALID_FLAGS);
380
381 /*
382 * Initialize globals.
383 */
384 int rc = RTOnceEx(&g_MemSaferOnce, rtMemSaferOnceInit, rtMemSaferOnceTerm, NULL);
385 if (RT_SUCCESS(rc))
386 {
387 /*
388 * Allocate a tracker node first.
389 */
390 PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTMemAllocZ(sizeof(RTMEMSAFERNODE));
391 if (pThis)
392 {
393 /*
394 * Prepare the allocation.
395 */
396 pThis->cbUser = cb;
397 pThis->offUser = (RTRandU32Ex(0, 128) * RTMEMSAFER_ALIGN) & PAGE_OFFSET_MASK;
398
399 size_t cbNeeded = pThis->offUser + pThis->cbUser;
400 cbNeeded = RT_ALIGN_Z(cbNeeded, PAGE_SIZE);
401
402 pThis->cPages = (uint32_t)(cbNeeded / PAGE_SIZE) + 2; /* +2 for guard pages */
403
404 /*
405 * Try allocate the memory, using the best allocator by default and
406 * falling back on the less safe one.
407 */
408 rc = rtMemSaferSupR3AllocPages(pThis);
409 if (RT_SUCCESS(rc))
410 pThis->enmAllocator = RTMEMSAFERALLOCATOR_SUPR3;
411 else if (!(fFlags & RTMEMSAFER_F_REQUIRE_NOT_PAGABLE))
412 {
413 rc = rtMemSaferMemAllocPages(pThis);
414 if (RT_SUCCESS(rc))
415 pThis->enmAllocator = RTMEMSAFERALLOCATOR_RTMEMPAGE;
416 }
417 if (RT_SUCCESS(rc))
418 {
419 /*
420 * Insert the node.
421 */
422 *ppvNew = pThis->Core.Key;
423 rtMemSaferNodeInsert(pThis); /* (Scrambles Core.Key) */
424 return VINF_SUCCESS;
425 }
426
427 RTMemFree(pThis);
428 }
429 else
430 rc = VERR_NO_MEMORY;
431 }
432 return rc;
433}
434RT_EXPORT_SYMBOL(RTMemSaferAllocZExTag);
435
436
437RTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW_DEF
438{
439 if (pv)
440 {
441 PRTMEMSAFERNODE pThis = rtMemSaferNodeRemove(pv);
442 AssertReturnVoid(pThis);
443 AssertMsg(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser));
444
445 /*
446 * Wipe the user memory first.
447 */
448 RTMemWipeThoroughly(pv, RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN), 3);
449
450 /*
451 * Free the pages.
452 */
453 uint8_t *pbPages = (uint8_t *)pv - pThis->offUser - PAGE_SIZE;
454 size_t cbPages = (size_t)pThis->cPages * PAGE_SIZE;
455 switch (pThis->enmAllocator)
456 {
457#ifdef IN_SUP_R3
458 case RTMEMSAFERALLOCATOR_SUPR3:
459 SUPR3PageProtect(pbPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
460 SUPR3PageProtect(pbPages, NIL_RTR0PTR, (uint32_t)(cbPages - PAGE_SIZE), PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
461 SUPR3PageFreeEx(pbPages, pThis->cPages);
462 break;
463#endif
464 case RTMEMSAFERALLOCATOR_RTMEMPAGE:
465 RTMemProtect(pbPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
466 RTMemProtect(pbPages + cbPages - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
467 RTMemPageFree(pbPages, cbPages);
468 break;
469
470 default:
471 AssertFailed();
472 }
473
474 /*
475 * Free the tracking node.
476 */
477 pThis->Core.Key = NULL;
478 pThis->offUser = 0;
479 pThis->cbUser = 0;
480 RTMemFree(pThis);
481 }
482 else
483 Assert(cb == 0);
484}
485RT_EXPORT_SYMBOL(RTMemSaferFree);
486
487
488/**
489 * The simplest reallocation method: allocate new block, copy over the data,
490 * free old block.
491 */
492static int rtMemSaferReallocSimpler(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag)
493{
494 void *pvNew;
495 int rc = RTMemSaferAllocZExTag(&pvNew, cbNew, fFlags, pszTag);
496 if (RT_SUCCESS(rc))
497 {
498 memcpy(pvNew, pvOld, RT_MIN(cbNew, cbOld));
499 RTMemSaferFree(pvOld, cbOld);
500 *ppvNew = pvNew;
501 }
502 return rc;
503}
504
505
506RTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW_DEF
507{
508 int rc;
509 /* Real realloc. */
510 if (cbNew && cbOld)
511 {
512 PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pvOld);
513 AssertReturn(pThis, VERR_INVALID_POINTER);
514 AssertMsgStmt(cbOld == pThis->cbUser, ("cbOld=%#zx != %#zx\n", cbOld, pThis->cbUser), cbOld = pThis->cbUser);
515
516 if (pThis->fFlags == fFlags)
517 {
518 if (cbNew > cbOld)
519 {
520 /*
521 * Is the enough room for us to grow?
522 */
523 size_t cbMax = (size_t)(pThis->cPages - 2) * PAGE_SIZE;
524 if (cbNew <= cbMax)
525 {
526 size_t const cbAdded = (cbNew - cbOld);
527 size_t const cbAfter = cbMax - pThis->offUser - cbOld;
528 if (cbAfter >= cbAdded)
529 {
530 /*
531 * Sufficient space after the current allocation.
532 */
533 uint8_t *pbNewSpace = (uint8_t *)pvOld + cbOld;
534 RT_BZERO(pbNewSpace, cbAdded);
535 *ppvNew = pvOld;
536 }
537 else
538 {
539 /*
540 * Have to move the allocation to make enough room at the
541 * end. In order to make it a little less predictable and
542 * maybe avoid a relocation or two in the next call, divide
543 * the page offset by four until it it fits.
544 */
545 AssertReturn(rtMemSaferNodeRemove(pvOld) == pThis, VERR_INTERNAL_ERROR_3);
546 uint32_t offNewUser = pThis->offUser;
547 do
548 offNewUser = offNewUser / 2;
549 while ((pThis->offUser - offNewUser) + cbAfter < cbAdded);
550 offNewUser &= ~(RTMEMSAFER_ALIGN - 1U);
551
552 uint32_t const cbMove = pThis->offUser - offNewUser;
553 uint8_t *pbNew = (uint8_t *)pvOld - cbMove;
554 memmove(pbNew, pvOld, cbOld);
555
556 RT_BZERO(pbNew + cbOld, cbAdded);
557 if (cbMove > cbAdded)
558 RTMemWipeThoroughly(pbNew + cbNew, cbMove - cbAdded, 3);
559
560 pThis->offUser = offNewUser;
561 pThis->Core.Key = pbNew;
562 *ppvNew = pbNew;
563
564 rtMemSaferNodeInsert(pThis);
565 }
566 Assert(((uintptr_t)*ppvNew & PAGE_OFFSET_MASK) == pThis->offUser);
567 pThis->cbUser = cbNew;
568 rc = VINF_SUCCESS;
569 }
570 else
571 {
572 /*
573 * Not enough space, allocate a new block and copy over the data.
574 */
575 rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
576 }
577 }
578 else
579 {
580 /*
581 * Shrinking the allocation, just wipe the memory that is no longer
582 * being used.
583 */
584 if (cbNew != cbOld)
585 {
586 uint8_t *pbAbandond = (uint8_t *)pvOld + cbNew;
587 RTMemWipeThoroughly(pbAbandond, cbOld - cbNew, 3);
588 }
589 pThis->cbUser = cbNew;
590 *ppvNew = pvOld;
591 rc = VINF_SUCCESS;
592 }
593 }
594 else if (!pThis->fFlags)
595 {
596 /*
597 * New flags added. Allocate a new block and copy over the old one.
598 */
599 rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
600 }
601 else
602 {
603 /* Compatible flags. */
604 AssertMsgFailed(("fFlags=%#x old=%#x\n", fFlags, pThis->fFlags));
605 rc = VERR_INVALID_FLAGS;
606 }
607 }
608 /*
609 * First allocation. Pass it on.
610 */
611 else if (!cbOld)
612 {
613 Assert(pvOld == NULL);
614 rc = RTMemSaferAllocZExTag(ppvNew, cbNew, fFlags, pszTag);
615 }
616 /*
617 * Free operation. Pass it on.
618 */
619 else
620 {
621 RTMemSaferFree(pvOld, cbOld);
622 *ppvNew = NULL;
623 rc = VINF_SUCCESS;
624 }
625 return rc;
626}
627RT_EXPORT_SYMBOL(RTMemSaferReallocZExTag);
628
629
630RTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
631{
632 void *pvNew = NULL;
633 int rc = RTMemSaferAllocZExTag(&pvNew, cb, 0 /*fFlags*/, pszTag);
634 if (RT_SUCCESS(rc))
635 return pvNew;
636 return NULL;
637}
638RT_EXPORT_SYMBOL(RTMemSaferAllocZTag);
639
640
641RTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
642{
643 void *pvNew = NULL;
644 int rc = RTMemSaferReallocZExTag(cbOld, pvOld, cbNew, &pvNew, 0 /*fFlags*/, pszTag);
645 if (RT_SUCCESS(rc))
646 return pvNew;
647 return NULL;
648}
649RT_EXPORT_SYMBOL(RTMemSaferReallocZTag);
650
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use