VirtualBox

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

Last change on this file since 61009 was 57432, checked in by vboxsync, 9 years ago

iprt/cdefs.h,*: Split RT_NO_THROW into prototype and definition macros named RT_NO_THROW_PROTO and RT_NO_THROW_DEF respecitively.

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