Coverage Report

Created: 2024-05-20 06:23

/src/nspr/pr/src/malloc/prmem.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
/*
7
** Thread safe versions of malloc, free, realloc, calloc and cfree.
8
*/
9
10
#include "primpl.h"
11
12
#ifdef _PR_ZONE_ALLOCATOR
13
14
/*
15
** The zone allocator code must use native mutexes and cannot
16
** use PRLocks because PR_NewLock calls PR_Calloc, resulting
17
** in cyclic dependency of initialization.
18
*/
19
20
#include <string.h>
21
22
union memBlkHdrUn;
23
24
typedef struct MemoryZoneStr {
25
    union memBlkHdrUn    *head;         /* free list */
26
    pthread_mutex_t       lock;
27
    size_t                blockSize;    /* size of blocks on this free list */
28
    PRUint32              locked;       /* current state of lock */
29
    PRUint32              contention;   /* counter: had to wait for lock */
30
    PRUint32              hits;         /* allocated from free list */
31
    PRUint32              misses;       /* had to call malloc */
32
    PRUint32              elements;     /* on free list */
33
} MemoryZone;
34
35
typedef union memBlkHdrUn {
36
    unsigned char filler[48];  /* fix the size of this beast */
37
    struct memBlkHdrStr {
38
        union memBlkHdrUn    *next;
39
        MemoryZone           *zone;
40
        size_t                blockSize;
41
        size_t                requestedSize;
42
        PRUint32              magic;
43
    } s;
44
} MemBlockHdr;
45
46
0
#define MEM_ZONES     7
47
0
#define THREAD_POOLS 11  /* prime number for modulus */
48
0
#define ZONE_MAGIC  0x0BADC0DE
49
50
static MemoryZone zones[MEM_ZONES][THREAD_POOLS];
51
52
static PRBool use_zone_allocator = PR_FALSE;
53
54
static void pr_ZoneFree(void *ptr);
55
56
void
57
_PR_DestroyZones(void)
58
0
{
59
0
    int i, j;
60
61
0
    if (!use_zone_allocator) {
62
0
        return;
63
0
    }
64
65
0
    for (j = 0; j < THREAD_POOLS; j++) {
66
0
        for (i = 0; i < MEM_ZONES; i++) {
67
0
            MemoryZone *mz = &zones[i][j];
68
0
            pthread_mutex_destroy(&mz->lock);
69
0
            while (mz->head) {
70
0
                MemBlockHdr *hdr = mz->head;
71
0
                mz->head = hdr->s.next;  /* unlink it */
72
0
                free(hdr);
73
0
                mz->elements--;
74
0
            }
75
0
        }
76
0
    }
77
0
    use_zone_allocator = PR_FALSE;
78
0
}
79
80
/*
81
** pr_FindSymbolInProg
82
**
83
** Find the specified data symbol in the program and return
84
** its address.
85
*/
86
87
#ifdef HAVE_DLL
88
89
#if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL)
90
91
#include <dlfcn.h>
92
93
static void *
94
pr_FindSymbolInProg(const char *name)
95
1
{
96
1
    void *h;
97
1
    void *sym;
98
99
1
    h = dlopen(0, RTLD_LAZY);
100
1
    if (h == NULL) {
101
0
        return NULL;
102
0
    }
103
1
    sym = dlsym(h, name);
104
1
    (void)dlclose(h);
105
1
    return sym;
106
1
}
107
108
#elif defined(USE_HPSHL)
109
110
#include <dl.h>
111
112
static void *
113
pr_FindSymbolInProg(const char *name)
114
{
115
    shl_t h = NULL;
116
    void *sym;
117
118
    if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1) {
119
        return NULL;
120
    }
121
    return sym;
122
}
123
124
#elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL)
125
126
static void *
127
pr_FindSymbolInProg(const char *name)
128
{
129
    /* FIXME: not implemented */
130
    return NULL;
131
}
132
133
#else
134
135
#error "The zone allocator is not supported on this platform"
136
137
#endif
138
139
#else /* !defined(HAVE_DLL) */
140
141
static void *
142
pr_FindSymbolInProg(const char *name)
143
{
144
    /* can't be implemented */
145
    return NULL;
146
}
147
148
#endif /* HAVE_DLL */
149
150
void
151
_PR_InitZones(void)
152
1
{
153
1
    int i, j;
154
1
    char *envp;
155
1
    PRBool *sym;
156
157
1
    if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) {
158
0
        use_zone_allocator = *sym;
159
1
    } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) {
160
0
        use_zone_allocator = (atoi(envp) == 1);
161
0
    }
162
163
1
    if (!use_zone_allocator) {
164
1
        return;
165
1
    }
166
167
0
    for (j = 0; j < THREAD_POOLS; j++) {
168
0
        for (i = 0; i < MEM_ZONES; i++) {
169
0
            MemoryZone *mz = &zones[i][j];
170
0
            int rv = pthread_mutex_init(&mz->lock, NULL);
171
0
            PR_ASSERT(0 == rv);
172
0
            if (rv != 0) {
173
0
                goto loser;
174
0
            }
175
0
            mz->blockSize = 16 << ( 2 * i);
176
0
        }
177
0
    }
178
0
    return;
179
180
0
loser:
181
0
    _PR_DestroyZones();
182
0
    return;
183
0
}
184
185
PR_IMPLEMENT(void)
186
PR_FPrintZoneStats(PRFileDesc *debug_out)
187
0
{
188
0
    int i, j;
189
190
0
    for (j = 0; j < THREAD_POOLS; j++) {
191
0
        for (i = 0; i < MEM_ZONES; i++) {
192
0
            MemoryZone   *mz   = &zones[i][j];
193
0
            MemoryZone    zone = *mz;
194
0
            if (zone.elements || zone.misses || zone.hits) {
195
0
                PR_fprintf(debug_out,
196
0
                           "pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n",
197
0
                           j, i, zone.blockSize, zone.elements,
198
0
                           zone.hits, zone.misses, zone.contention);
199
0
            }
200
0
        }
201
0
    }
202
0
}
203
204
static void *
205
pr_ZoneMalloc(PRUint32 size)
206
0
{
207
0
    void         *rv;
208
0
    unsigned int  zone;
209
0
    size_t        blockSize;
210
0
    MemBlockHdr  *mb, *mt;
211
0
    MemoryZone   *mz;
212
213
    /* Always allocate a non-zero amount of bytes */
214
0
    if (size < 1) {
215
0
        size = 1;
216
0
    }
217
0
    for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) {
218
0
        if (size <= blockSize) {
219
0
            break;
220
0
        }
221
0
    }
222
0
    if (zone < MEM_ZONES) {
223
0
        pthread_t me = pthread_self();
224
0
        unsigned int pool = (PRUptrdiff)me % THREAD_POOLS;
225
0
        PRUint32     wasLocked;
226
0
        mz = &zones[zone][pool];
227
0
        wasLocked = mz->locked;
228
0
        pthread_mutex_lock(&mz->lock);
229
0
        mz->locked = 1;
230
0
        if (wasLocked) {
231
0
            mz->contention++;
232
0
        }
233
0
        if (mz->head) {
234
0
            mb = mz->head;
235
0
            PR_ASSERT(mb->s.magic == ZONE_MAGIC);
236
0
            PR_ASSERT(mb->s.zone  == mz);
237
0
            PR_ASSERT(mb->s.blockSize == blockSize);
238
0
            PR_ASSERT(mz->blockSize == blockSize);
239
240
0
            mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
241
0
            PR_ASSERT(mt->s.magic == ZONE_MAGIC);
242
0
            PR_ASSERT(mt->s.zone  == mz);
243
0
            PR_ASSERT(mt->s.blockSize == blockSize);
244
245
0
            mz->hits++;
246
0
            mz->elements--;
247
0
            mz->head = mb->s.next;    /* take off free list */
248
0
            mz->locked = 0;
249
0
            pthread_mutex_unlock(&mz->lock);
250
251
0
            mt->s.next          = mb->s.next          = NULL;
252
0
            mt->s.requestedSize = mb->s.requestedSize = size;
253
254
0
            rv = (void *)(mb + 1);
255
0
            return rv;
256
0
        }
257
258
0
        mz->misses++;
259
0
        mz->locked = 0;
260
0
        pthread_mutex_unlock(&mz->lock);
261
262
0
        mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
263
0
        if (!mb) {
264
0
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
265
0
            return NULL;
266
0
        }
267
0
        mb->s.next          = NULL;
268
0
        mb->s.zone          = mz;
269
0
        mb->s.magic         = ZONE_MAGIC;
270
0
        mb->s.blockSize     = blockSize;
271
0
        mb->s.requestedSize = size;
272
273
0
        mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
274
0
        memcpy(mt, mb, sizeof *mb);
275
276
0
        rv = (void *)(mb + 1);
277
0
        return rv;
278
0
    }
279
280
    /* size was too big.  Create a block with no zone */
281
0
    blockSize = (size & 15) ? size + 16 - (size & 15) : size;
282
0
    mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
283
0
    if (!mb) {
284
0
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
285
0
        return NULL;
286
0
    }
287
0
    mb->s.next          = NULL;
288
0
    mb->s.zone          = NULL;
289
0
    mb->s.magic         = ZONE_MAGIC;
290
0
    mb->s.blockSize     = blockSize;
291
0
    mb->s.requestedSize = size;
292
293
0
    mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
294
0
    memcpy(mt, mb, sizeof *mb);
295
296
0
    rv = (void *)(mb + 1);
297
0
    return rv;
298
0
}
299
300
301
static void *
302
pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize)
303
0
{
304
0
    PRUint32 size = nelem * elsize;
305
0
    void *p = pr_ZoneMalloc(size);
306
0
    if (p) {
307
0
        memset(p, 0, size);
308
0
    }
309
0
    return p;
310
0
}
311
312
static void *
313
pr_ZoneRealloc(void *oldptr, PRUint32 bytes)
314
0
{
315
0
    void         *rv;
316
0
    MemBlockHdr  *mb;
317
0
    int           ours;
318
0
    MemBlockHdr   phony;
319
320
0
    if (!oldptr) {
321
0
        return pr_ZoneMalloc(bytes);
322
0
    }
323
0
    mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb));
324
0
    if (mb->s.magic != ZONE_MAGIC) {
325
        /* Maybe this just came from ordinary malloc */
326
0
#ifdef DEBUG
327
0
        fprintf(stderr,
328
0
                "Warning: reallocing memory block %p from ordinary malloc\n",
329
0
                oldptr);
330
0
#endif
331
        /*
332
         * We are going to realloc oldptr.  If realloc succeeds, the
333
         * original value of oldptr will point to freed memory.  So this
334
         * function must not fail after a successfull realloc call.  We
335
         * must perform any operation that may fail before the realloc
336
         * call.
337
         */
338
0
        rv = pr_ZoneMalloc(bytes);  /* this may fail */
339
0
        if (!rv) {
340
0
            return rv;
341
0
        }
342
343
        /* We don't know how big it is.  But we can fix that. */
344
0
        oldptr = realloc(oldptr, bytes);
345
        /*
346
         * If realloc returns NULL, this function loses the original
347
         * value of oldptr.  This isn't a leak because the caller of
348
         * this function still has the original value of oldptr.
349
         */
350
0
        if (!oldptr) {
351
0
            if (bytes) {
352
0
                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
353
0
                pr_ZoneFree(rv);
354
0
                return oldptr;
355
0
            }
356
0
        }
357
0
        phony.s.requestedSize = bytes;
358
0
        mb = &phony;
359
0
        ours = 0;
360
0
    } else {
361
0
        size_t blockSize = mb->s.blockSize;
362
0
        MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
363
364
0
        PR_ASSERT(mt->s.magic == ZONE_MAGIC);
365
0
        PR_ASSERT(mt->s.zone  == mb->s.zone);
366
0
        PR_ASSERT(mt->s.blockSize == blockSize);
367
368
0
        if (bytes <= blockSize) {
369
            /* The block is already big enough. */
370
0
            mt->s.requestedSize = mb->s.requestedSize = bytes;
371
0
            return oldptr;
372
0
        }
373
0
        ours = 1;
374
0
        rv = pr_ZoneMalloc(bytes);
375
0
        if (!rv) {
376
0
            return rv;
377
0
        }
378
0
    }
379
380
0
    if (oldptr && mb->s.requestedSize) {
381
0
        memcpy(rv, oldptr, mb->s.requestedSize);
382
0
    }
383
0
    if (ours) {
384
0
        pr_ZoneFree(oldptr);
385
0
    }
386
0
    else if (oldptr) {
387
0
        free(oldptr);
388
0
    }
389
0
    return rv;
390
0
}
391
392
static void
393
pr_ZoneFree(void *ptr)
394
0
{
395
0
    MemBlockHdr  *mb, *mt;
396
0
    MemoryZone   *mz;
397
0
    size_t        blockSize;
398
0
    PRUint32      wasLocked;
399
400
0
    if (!ptr) {
401
0
        return;
402
0
    }
403
404
0
    mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb));
405
406
0
    if (mb->s.magic != ZONE_MAGIC) {
407
        /* maybe this came from ordinary malloc */
408
0
#ifdef DEBUG
409
0
        fprintf(stderr,
410
0
                "Warning: freeing memory block %p from ordinary malloc\n", ptr);
411
0
#endif
412
0
        free(ptr);
413
0
        return;
414
0
    }
415
416
0
    blockSize = mb->s.blockSize;
417
0
    mz        = mb->s.zone;
418
0
    mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
419
0
    PR_ASSERT(mt->s.magic == ZONE_MAGIC);
420
0
    PR_ASSERT(mt->s.zone  == mz);
421
0
    PR_ASSERT(mt->s.blockSize == blockSize);
422
0
    if (!mz) {
423
0
        PR_ASSERT(blockSize > 65536);
424
        /* This block was not in any zone.  Just free it. */
425
0
        free(mb);
426
0
        return;
427
0
    }
428
0
    PR_ASSERT(mz->blockSize == blockSize);
429
0
    wasLocked = mz->locked;
430
0
    pthread_mutex_lock(&mz->lock);
431
0
    mz->locked = 1;
432
0
    if (wasLocked) {
433
0
        mz->contention++;
434
0
    }
435
0
    mt->s.next = mb->s.next = mz->head;        /* put on head of list */
436
0
    mz->head = mb;
437
0
    mz->elements++;
438
0
    mz->locked = 0;
439
0
    pthread_mutex_unlock(&mz->lock);
440
0
}
441
442
PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
443
255k
{
444
255k
    if (!_pr_initialized) {
445
0
        _PR_ImplicitInitialization();
446
0
    }
447
448
255k
    return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size);
449
255k
}
450
451
PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
452
380k
{
453
380k
    if (!_pr_initialized) {
454
0
        _PR_ImplicitInitialization();
455
0
    }
456
457
380k
    return use_zone_allocator ?
458
380k
           pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize);
459
380k
}
460
461
PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
462
83.1k
{
463
83.1k
    if (!_pr_initialized) {
464
0
        _PR_ImplicitInitialization();
465
0
    }
466
467
83.1k
    return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size);
468
83.1k
}
469
470
PR_IMPLEMENT(void) PR_Free(void *ptr)
471
635k
{
472
635k
    if (use_zone_allocator) {
473
0
        pr_ZoneFree(ptr);
474
0
    }
475
635k
    else {
476
635k
        free(ptr);
477
635k
    }
478
635k
}
479
480
#else /* !defined(_PR_ZONE_ALLOCATOR) */
481
482
/*
483
** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply
484
** call their libc equivalents now.  This may seem redundant, but it
485
** ensures that we are calling into the same runtime library.  On
486
** Win32, it is possible to have multiple runtime libraries (e.g.,
487
** objects compiled with /MD and /MDd) in the same process, and
488
** they maintain separate heaps, which cannot be mixed.
489
*/
490
PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
491
{
492
#if defined (WIN16)
493
    return PR_MD_malloc( (size_t) size);
494
#else
495
    return malloc(size);
496
#endif
497
}
498
499
PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
500
{
501
#if defined (WIN16)
502
    return PR_MD_calloc( (size_t)nelem, (size_t)elsize );
503
504
#else
505
    return calloc(nelem, elsize);
506
#endif
507
}
508
509
PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
510
{
511
#if defined (WIN16)
512
    return PR_MD_realloc( ptr, (size_t) size);
513
#else
514
    return realloc(ptr, size);
515
#endif
516
}
517
518
PR_IMPLEMENT(void) PR_Free(void *ptr)
519
{
520
#if defined (WIN16)
521
    PR_MD_free( ptr );
522
#else
523
    free(ptr);
524
#endif
525
}
526
527
#endif /* _PR_ZONE_ALLOCATOR */
528
529
/*
530
** Complexity alert!
531
**
532
** If malloc/calloc/free (etc.) were implemented to use pr lock's then
533
** the entry points could block when called if some other thread had the
534
** lock.
535
**
536
** Most of the time this isn't a problem. However, in the case that we
537
** are using the thread safe malloc code after PR_Init but before
538
** PR_AttachThread has been called (on a native thread that nspr has yet
539
** to be told about) we could get royally screwed if the lock was busy
540
** and we tried to context switch the thread away. In this scenario
541
**  PR_CURRENT_THREAD() == NULL
542
**
543
** To avoid this unfortunate case, we use the low level locking
544
** facilities for malloc protection instead of the slightly higher level
545
** locking. This makes malloc somewhat faster so maybe it's a good thing
546
** anyway.
547
*/
548
#ifdef _PR_OVERRIDE_MALLOC
549
550
/* Imports */
551
extern void *_PR_UnlockedMalloc(size_t size);
552
extern void *_PR_UnlockedMemalign(size_t alignment, size_t size);
553
extern void _PR_UnlockedFree(void *ptr);
554
extern void *_PR_UnlockedRealloc(void *ptr, size_t size);
555
extern void *_PR_UnlockedCalloc(size_t n, size_t elsize);
556
557
static PRBool _PR_malloc_initialised = PR_FALSE;
558
559
#ifdef _PR_PTHREADS
560
static pthread_mutex_t _PR_MD_malloc_crustylock;
561
562
#define _PR_Lock_Malloc() {                     \
563
                    if(PR_TRUE == _PR_malloc_initialised) { \
564
                    PRStatus rv;            \
565
                    rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \
566
                    PR_ASSERT(0 == rv);     \
567
                }
568
569
#define _PR_Unlock_Malloc()     if(PR_TRUE == _PR_malloc_initialised) { \
570
                    PRStatus rv;            \
571
                    rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \
572
                    PR_ASSERT(0 == rv);     \
573
                }                   \
574
              }
575
#else /* _PR_PTHREADS */
576
static _MDLock _PR_MD_malloc_crustylock;
577
578
#define _PR_Lock_Malloc() {                     \
579
               PRIntn _is;                  \
580
                    if(PR_TRUE == _PR_malloc_initialised) { \
581
                if (_PR_MD_CURRENT_THREAD() &&      \
582
                    !_PR_IS_NATIVE_THREAD(      \
583
                    _PR_MD_CURRENT_THREAD()))   \
584
                        _PR_INTSOFF(_is);   \
585
                    _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
586
                }
587
588
#define _PR_Unlock_Malloc()     if(PR_TRUE == _PR_malloc_initialised) { \
589
                    _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
590
                if (_PR_MD_CURRENT_THREAD() &&      \
591
                    !_PR_IS_NATIVE_THREAD(      \
592
                    _PR_MD_CURRENT_THREAD()))   \
593
                        _PR_INTSON(_is);    \
594
                }                   \
595
              }
596
#endif /* _PR_PTHREADS */
597
598
PR_IMPLEMENT(PRStatus) _PR_MallocInit(void)
599
{
600
    PRStatus rv = PR_SUCCESS;
601
602
    if( PR_TRUE == _PR_malloc_initialised ) {
603
        return PR_SUCCESS;
604
    }
605
606
#ifdef _PR_PTHREADS
607
    {
608
        int status;
609
        pthread_mutexattr_t mattr;
610
611
        status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr);
612
        PR_ASSERT(0 == status);
613
        status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr);
614
        PR_ASSERT(0 == status);
615
        status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr);
616
        PR_ASSERT(0 == status);
617
    }
618
#else /* _PR_PTHREADS */
619
    _MD_NEW_LOCK(&_PR_MD_malloc_crustylock);
620
#endif /* _PR_PTHREADS */
621
622
    if( PR_SUCCESS == rv )
623
    {
624
        _PR_malloc_initialised = PR_TRUE;
625
    }
626
627
    return rv;
628
}
629
630
void *malloc(size_t size)
631
{
632
    void *p;
633
    _PR_Lock_Malloc();
634
    p = _PR_UnlockedMalloc(size);
635
    _PR_Unlock_Malloc();
636
    return p;
637
}
638
639
void free(void *ptr)
640
{
641
    _PR_Lock_Malloc();
642
    _PR_UnlockedFree(ptr);
643
    _PR_Unlock_Malloc();
644
}
645
646
void *realloc(void *ptr, size_t size)
647
{
648
    void *p;
649
    _PR_Lock_Malloc();
650
    p = _PR_UnlockedRealloc(ptr, size);
651
    _PR_Unlock_Malloc();
652
    return p;
653
}
654
655
void *calloc(size_t n, size_t elsize)
656
{
657
    void *p;
658
    _PR_Lock_Malloc();
659
    p = _PR_UnlockedCalloc(n, elsize);
660
    _PR_Unlock_Malloc();
661
    return p;
662
}
663
664
void cfree(void *p)
665
{
666
    _PR_Lock_Malloc();
667
    _PR_UnlockedFree(p);
668
    _PR_Unlock_Malloc();
669
}
670
671
void _PR_InitMem(void)
672
{
673
    PRStatus rv;
674
    rv = _PR_MallocInit();
675
    PR_ASSERT(PR_SUCCESS == rv);
676
}
677
678
#endif /* _PR_OVERRIDE_MALLOC */