Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: mozilla/security/nss/lib/base/arena.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/exports_win.def ('k') | mozilla/security/nss/lib/base/base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #ifdef DEBUG
6 static const char CVS_ID[] = "@(#) $RCSfile: arena.c,v $ $Revision: 1.15 $ $Date : 2012/07/06 18:19:32 $";
7 #endif /* DEBUG */
8
9 /*
10 * arena.c
11 *
12 * This contains the implementation of NSS's thread-safe arenas.
13 */
14
15 #ifndef BASE_H
16 #include "base.h"
17 #endif /* BASE_H */
18
19 #ifdef ARENA_THREADMARK
20 #include "prthread.h"
21 #endif /* ARENA_THREADMARK */
22
23 #include "prlock.h"
24 #include "plarena.h"
25
26 #include <string.h>
27
28 /*
29 * NSSArena
30 *
31 * This is based on NSPR's arena code, but it is threadsafe.
32 *
33 * The public methods relating to this type are:
34 *
35 * NSSArena_Create -- constructor
36 * NSSArena_Destroy
37 * NSS_ZAlloc
38 * NSS_ZRealloc
39 * NSS_ZFreeIf
40 *
41 * The nonpublic methods relating to this type are:
42 *
43 * nssArena_Create -- constructor
44 * nssArena_Destroy
45 * nssArena_Mark
46 * nssArena_Release
47 * nssArena_Unmark
48 *
49 * nss_ZAlloc
50 * nss_ZFreeIf
51 * nss_ZRealloc
52 *
53 * In debug builds, the following calls are available:
54 *
55 * nssArena_verifyPointer
56 * nssArena_registerDestructor
57 * nssArena_deregisterDestructor
58 */
59
60 struct NSSArenaStr {
61 PLArenaPool pool;
62 PRLock *lock;
63 #ifdef ARENA_THREADMARK
64 PRThread *marking_thread;
65 nssArenaMark *first_mark;
66 nssArenaMark *last_mark;
67 #endif /* ARENA_THREADMARK */
68 #ifdef ARENA_DESTRUCTOR_LIST
69 struct arena_destructor_node *first_destructor;
70 struct arena_destructor_node *last_destructor;
71 #endif /* ARENA_DESTRUCTOR_LIST */
72 };
73
74 /*
75 * nssArenaMark
76 *
77 * This type is used to mark the current state of an NSSArena.
78 */
79
80 struct nssArenaMarkStr {
81 PRUint32 magic;
82 void *mark;
83 #ifdef ARENA_THREADMARK
84 nssArenaMark *next;
85 #endif /* ARENA_THREADMARK */
86 #ifdef ARENA_DESTRUCTOR_LIST
87 struct arena_destructor_node *next_destructor;
88 struct arena_destructor_node *prev_destructor;
89 #endif /* ARENA_DESTRUCTOR_LIST */
90 };
91
92 #define MARK_MAGIC 0x4d41524b /* "MARK" how original */
93
94 /*
95 * But first, the pointer-tracking code
96 */
97 #ifdef DEBUG
98 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
99
100 static nssPointerTracker arena_pointer_tracker;
101
102 static PRStatus
103 arena_add_pointer
104 (
105 const NSSArena *arena
106 )
107 {
108 PRStatus rv;
109
110 rv = nssPointerTracker_initialize(&arena_pointer_tracker);
111 if( PR_SUCCESS != rv ) {
112 return rv;
113 }
114
115 rv = nssPointerTracker_add(&arena_pointer_tracker, arena);
116 if( PR_SUCCESS != rv ) {
117 NSSError e = NSS_GetError();
118 if( NSS_ERROR_NO_MEMORY != e ) {
119 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
120 }
121
122 return rv;
123 }
124
125 return PR_SUCCESS;
126 }
127
128 static PRStatus
129 arena_remove_pointer
130 (
131 const NSSArena *arena
132 )
133 {
134 PRStatus rv;
135
136 rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);
137 if( PR_SUCCESS != rv ) {
138 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
139 }
140
141 return rv;
142 }
143
144 /*
145 * nssArena_verifyPointer
146 *
147 * This method is only present in debug builds.
148 *
149 * If the specified pointer is a valid pointer to an NSSArena object,
150 * this routine will return PR_SUCCESS. Otherwise, it will put an
151 * error on the error stack and return PR_FAILURE.
152 *
153 * The error may be one of the following values:
154 * NSS_ERROR_INVALID_ARENA
155 *
156 * Return value:
157 * PR_SUCCESS if the pointer is valid
158 * PR_FAILURE if it isn't
159 */
160
161 NSS_IMPLEMENT PRStatus
162 nssArena_verifyPointer
163 (
164 const NSSArena *arena
165 )
166 {
167 PRStatus rv;
168
169 rv = nssPointerTracker_initialize(&arena_pointer_tracker);
170 if( PR_SUCCESS != rv ) {
171 /*
172 * This is a little disingenious. We have to initialize the
173 * tracker, because someone could "legitimately" try to verify
174 * an arena pointer before one is ever created. And this step
175 * might fail, due to lack of memory. But the only way that
176 * this step can fail is if it's doing the call_once stuff,
177 * (later calls just no-op). And if it didn't no-op, there
178 * aren't any valid arenas.. so the argument certainly isn't one.
179 */
180 nss_SetError(NSS_ERROR_INVALID_ARENA);
181 return PR_FAILURE;
182 }
183
184 rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);
185 if( PR_SUCCESS != rv ) {
186 nss_SetError(NSS_ERROR_INVALID_ARENA);
187 return PR_FAILURE;
188 }
189
190 return PR_SUCCESS;
191 }
192 #endif /* DEBUG */
193
194 #ifdef ARENA_DESTRUCTOR_LIST
195
196 struct arena_destructor_node {
197 struct arena_destructor_node *next;
198 struct arena_destructor_node *prev;
199 void (*destructor)(void *argument);
200 void *arg;
201 };
202
203 /*
204 * nssArena_registerDestructor
205 *
206 * This routine stores a pointer to a callback and an arbitrary
207 * pointer-sized argument in the arena, at the current point in
208 * the mark stack. If the arena is destroyed, or an "earlier"
209 * mark is released, then this destructor will be called at that
210 * time. Note that the destructor will be called with the arena
211 * locked, which means the destructor may free memory in that
212 * arena, but it may not allocate or cause to be allocated any
213 * memory. This callback facility was included to support our
214 * debug-version pointer-tracker feature; overuse runs counter to
215 * the the original intent of arenas. This routine returns a
216 * PRStatus value; if successful, it will return PR_SUCCESS. If
217 * unsuccessful, it will set an error on the error stack and
218 * return PR_FAILURE.
219 *
220 * The error may be one of the following values:
221 * NSS_ERROR_INVALID_ARENA
222 * NSS_ERROR_NO_MEMORY
223 *
224 * Return value:
225 * PR_SUCCESS
226 * PR_FAILURE
227 */
228
229 NSS_IMPLEMENT PRStatus
230 nssArena_registerDestructor
231 (
232 NSSArena *arena,
233 void (*destructor)(void *argument),
234 void *arg
235 )
236 {
237 struct arena_destructor_node *it;
238
239 #ifdef NSSDEBUG
240 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
241 return PR_FAILURE;
242 }
243 #endif /* NSSDEBUG */
244
245 it = nss_ZNEW(arena, struct arena_destructor_node);
246 if( (struct arena_destructor_node *)NULL == it ) {
247 return PR_FAILURE;
248 }
249
250 it->prev = arena->last_destructor;
251 arena->last_destructor->next = it;
252 arena->last_destructor = it;
253 it->destructor = destructor;
254 it->arg = arg;
255
256 if( (nssArenaMark *)NULL != arena->last_mark ) {
257 arena->last_mark->prev_destructor = it->prev;
258 arena->last_mark->next_destructor = it->next;
259 }
260
261 return PR_SUCCESS;
262 }
263
264 NSS_IMPLEMENT PRStatus
265 nssArena_deregisterDestructor
266 (
267 NSSArena *arena,
268 void (*destructor)(void *argument),
269 void *arg
270 )
271 {
272 struct arena_destructor_node *it;
273
274 #ifdef NSSDEBUG
275 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
276 return PR_FAILURE;
277 }
278 #endif /* NSSDEBUG */
279
280 for( it = arena->first_destructor; it; it = it->next ) {
281 if( (it->destructor == destructor) && (it->arg == arg) ) {
282 break;
283 }
284 }
285
286 if( (struct arena_destructor_node *)NULL == it ) {
287 nss_SetError(NSS_ERROR_NOT_FOUND);
288 return PR_FAILURE;
289 }
290
291 if( it == arena->first_destructor ) {
292 arena->first_destructor = it->next;
293 }
294
295 if( it == arena->last_destructor ) {
296 arena->last_destructor = it->prev;
297 }
298
299 if( (struct arena_destructor_node *)NULL != it->prev ) {
300 it->prev->next = it->next;
301 }
302
303 if( (struct arena_destructor_node *)NULL != it->next ) {
304 it->next->prev = it->prev;
305 }
306
307 {
308 nssArenaMark *m;
309 for( m = arena->first_mark; m; m = m->next ) {
310 if( m->next_destructor == it ) {
311 m->next_destructor = it->next;
312 }
313 if( m->prev_destructor == it ) {
314 m->prev_destructor = it->prev;
315 }
316 }
317 }
318
319 nss_ZFreeIf(it);
320 return PR_SUCCESS;
321 }
322
323 static void
324 nss_arena_call_destructor_chain
325 (
326 struct arena_destructor_node *it
327 )
328 {
329 for( ; it ; it = it->next ) {
330 (*(it->destructor))(it->arg);
331 }
332 }
333
334 #endif /* ARENA_DESTRUCTOR_LIST */
335
336 /*
337 * NSSArena_Create
338 *
339 * This routine creates a new memory arena. This routine may return
340 * NULL upon error, in which case it will have created an error stack.
341 *
342 * The top-level error may be one of the following values:
343 * NSS_ERROR_NO_MEMORY
344 *
345 * Return value:
346 * NULL upon error
347 * A pointer to an NSSArena upon success
348 */
349
350 NSS_IMPLEMENT NSSArena *
351 NSSArena_Create
352 (
353 void
354 )
355 {
356 nss_ClearErrorStack();
357 return nssArena_Create();
358 }
359
360 /*
361 * nssArena_Create
362 *
363 * This routine creates a new memory arena. This routine may return
364 * NULL upon error, in which case it will have set an error on the
365 * error stack.
366 *
367 * The error may be one of the following values:
368 * NSS_ERROR_NO_MEMORY
369 *
370 * Return value:
371 * NULL upon error
372 * A pointer to an NSSArena upon success
373 */
374
375 NSS_IMPLEMENT NSSArena *
376 nssArena_Create
377 (
378 void
379 )
380 {
381 NSSArena *rv = (NSSArena *)NULL;
382
383 rv = nss_ZNEW((NSSArena *)NULL, NSSArena);
384 if( (NSSArena *)NULL == rv ) {
385 nss_SetError(NSS_ERROR_NO_MEMORY);
386 return (NSSArena *)NULL;
387 }
388
389 rv->lock = PR_NewLock();
390 if( (PRLock *)NULL == rv->lock ) {
391 (void)nss_ZFreeIf(rv);
392 nss_SetError(NSS_ERROR_NO_MEMORY);
393 return (NSSArena *)NULL;
394 }
395
396 /*
397 * Arena sizes. The current security code has 229 occurrences of
398 * PORT_NewArena. The default chunksizes specified break down as
399 *
400 * Size Mult. Specified as
401 * 512 1 512
402 * 1024 7 1024
403 * 2048 5 2048
404 * 2048 5 CRMF_DEFAULT_ARENA_SIZE
405 * 2048 190 DER_DEFAULT_CHUNKSIZE
406 * 2048 20 SEC_ASN1_DEFAULT_ARENA_SIZE
407 * 4096 1 4096
408 *
409 * Obviously this "default chunksize" flexibility isn't very
410 * useful to us, so I'll just pick 2048.
411 */
412
413 PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));
414
415 #ifdef DEBUG
416 {
417 PRStatus st;
418 st = arena_add_pointer(rv);
419 if( PR_SUCCESS != st ) {
420 PL_FinishArenaPool(&rv->pool);
421 PR_DestroyLock(rv->lock);
422 (void)nss_ZFreeIf(rv);
423 return (NSSArena *)NULL;
424 }
425 }
426 #endif /* DEBUG */
427
428 return rv;
429 }
430
431 /*
432 * NSSArena_Destroy
433 *
434 * This routine will destroy the specified arena, freeing all memory
435 * allocated from it. This routine returns a PRStatus value; if
436 * successful, it will return PR_SUCCESS. If unsuccessful, it will
437 * create an error stack and return PR_FAILURE.
438 *
439 * The top-level error may be one of the following values:
440 * NSS_ERROR_INVALID_ARENA
441 *
442 * Return value:
443 * PR_SUCCESS upon success
444 * PR_FAILURE upon failure
445 */
446
447 NSS_IMPLEMENT PRStatus
448 NSSArena_Destroy
449 (
450 NSSArena *arena
451 )
452 {
453 nss_ClearErrorStack();
454
455 #ifdef DEBUG
456 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
457 return PR_FAILURE;
458 }
459 #endif /* DEBUG */
460
461 return nssArena_Destroy(arena);
462 }
463
464 /*
465 * nssArena_Destroy
466 *
467 * This routine will destroy the specified arena, freeing all memory
468 * allocated from it. This routine returns a PRStatus value; if
469 * successful, it will return PR_SUCCESS. If unsuccessful, it will
470 * set an error on the error stack and return PR_FAILURE.
471 *
472 * The error may be one of the following values:
473 * NSS_ERROR_INVALID_ARENA
474 *
475 * Return value:
476 * PR_SUCCESS
477 * PR_FAILURE
478 */
479
480 NSS_IMPLEMENT PRStatus
481 nssArena_Destroy
482 (
483 NSSArena *arena
484 )
485 {
486 PRLock *lock;
487
488 #ifdef NSSDEBUG
489 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
490 return PR_FAILURE;
491 }
492 #endif /* NSSDEBUG */
493
494 if( (PRLock *)NULL == arena->lock ) {
495 /* Just got destroyed */
496 nss_SetError(NSS_ERROR_INVALID_ARENA);
497 return PR_FAILURE;
498 }
499 PR_Lock(arena->lock);
500
501 #ifdef DEBUG
502 if( PR_SUCCESS != arena_remove_pointer(arena) ) {
503 PR_Unlock(arena->lock);
504 return PR_FAILURE;
505 }
506 #endif /* DEBUG */
507
508 #ifdef ARENA_DESTRUCTOR_LIST
509 /* Note that the arena is locked at this time */
510 nss_arena_call_destructor_chain(arena->first_destructor);
511 #endif /* ARENA_DESTRUCTOR_LIST */
512
513 PL_FinishArenaPool(&arena->pool);
514 lock = arena->lock;
515 arena->lock = (PRLock *)NULL;
516 PR_Unlock(lock);
517 PR_DestroyLock(lock);
518 (void)nss_ZFreeIf(arena);
519 return PR_SUCCESS;
520 }
521
522 static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size);
523
524 /*
525 * nssArena_Mark
526 *
527 * This routine "marks" the current state of an arena. Space
528 * allocated after the arena has been marked can be freed by
529 * releasing the arena back to the mark with nssArena_Release,
530 * or committed by calling nssArena_Unmark. When successful,
531 * this routine returns a valid nssArenaMark pointer. This
532 * routine may return NULL upon error, in which case it will
533 * have set an error on the error stack.
534 *
535 * The error may be one of the following values:
536 * NSS_ERROR_INVALID_ARENA
537 * NSS_ERROR_NO_MEMORY
538 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
539 *
540 * Return value:
541 * NULL upon failure
542 * An nssArenaMark pointer upon success
543 */
544
545 NSS_IMPLEMENT nssArenaMark *
546 nssArena_Mark
547 (
548 NSSArena *arena
549 )
550 {
551 nssArenaMark *rv;
552 void *p;
553
554 #ifdef NSSDEBUG
555 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
556 return (nssArenaMark *)NULL;
557 }
558 #endif /* NSSDEBUG */
559
560 if( (PRLock *)NULL == arena->lock ) {
561 /* Just got destroyed */
562 nss_SetError(NSS_ERROR_INVALID_ARENA);
563 return (nssArenaMark *)NULL;
564 }
565 PR_Lock(arena->lock);
566
567 #ifdef ARENA_THREADMARK
568 if( (PRThread *)NULL == arena->marking_thread ) {
569 /* Unmarked. Store our thread ID */
570 arena->marking_thread = PR_GetCurrentThread();
571 /* This call never fails. */
572 } else {
573 /* Marked. Verify it's the current thread */
574 if( PR_GetCurrentThread() != arena->marking_thread ) {
575 PR_Unlock(arena->lock);
576 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
577 return (nssArenaMark *)NULL;
578 }
579 }
580 #endif /* ARENA_THREADMARK */
581
582 p = PL_ARENA_MARK(&arena->pool);
583 /* No error possible */
584
585 /* Do this after the mark */
586 rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark));
587 if( (nssArenaMark *)NULL == rv ) {
588 PR_Unlock(arena->lock);
589 nss_SetError(NSS_ERROR_NO_MEMORY);
590 return (nssArenaMark *)NULL;
591 }
592
593 #ifdef ARENA_THREADMARK
594 if ( (nssArenaMark *)NULL == arena->first_mark) {
595 arena->first_mark = rv;
596 arena->last_mark = rv;
597 } else {
598 arena->last_mark->next = rv;
599 arena->last_mark = rv;
600 }
601 #endif /* ARENA_THREADMARK */
602
603 rv->mark = p;
604 rv->magic = MARK_MAGIC;
605
606 #ifdef ARENA_DESTRUCTOR_LIST
607 rv->prev_destructor = arena->last_destructor;
608 #endif /* ARENA_DESTRUCTOR_LIST */
609
610 PR_Unlock(arena->lock);
611
612 return rv;
613 }
614
615 /*
616 * nss_arena_unmark_release
617 *
618 * This static routine implements the routines nssArena_Release
619 * ans nssArena_Unmark, which are almost identical.
620 */
621
622 static PRStatus
623 nss_arena_unmark_release
624 (
625 NSSArena *arena,
626 nssArenaMark *arenaMark,
627 PRBool release
628 )
629 {
630 void *inner_mark;
631
632 #ifdef NSSDEBUG
633 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
634 return PR_FAILURE;
635 }
636 #endif /* NSSDEBUG */
637
638 if( MARK_MAGIC != arenaMark->magic ) {
639 nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
640 return PR_FAILURE;
641 }
642
643 if( (PRLock *)NULL == arena->lock ) {
644 /* Just got destroyed */
645 nss_SetError(NSS_ERROR_INVALID_ARENA);
646 return PR_FAILURE;
647 }
648 PR_Lock(arena->lock);
649
650 #ifdef ARENA_THREADMARK
651 if( (PRThread *)NULL != arena->marking_thread ) {
652 if( PR_GetCurrentThread() != arena->marking_thread ) {
653 PR_Unlock(arena->lock);
654 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
655 return PR_FAILURE;
656 }
657 }
658 #endif /* ARENA_THREADMARK */
659
660 if( MARK_MAGIC != arenaMark->magic ) {
661 /* Just got released */
662 PR_Unlock(arena->lock);
663 nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
664 return PR_FAILURE;
665 }
666
667 arenaMark->magic = 0;
668 inner_mark = arenaMark->mark;
669
670 #ifdef ARENA_THREADMARK
671 {
672 nssArenaMark **pMark = &arena->first_mark;
673 nssArenaMark *rest;
674 nssArenaMark *last = (nssArenaMark *)NULL;
675
676 /* Find this mark */
677 while( *pMark != arenaMark ) {
678 last = *pMark;
679 pMark = &(*pMark)->next;
680 }
681
682 /* Remember the pointer, then zero it */
683 rest = (*pMark)->next;
684 *pMark = (nssArenaMark *)NULL;
685
686 arena->last_mark = last;
687
688 /* Invalidate any later marks being implicitly released */
689 for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) {
690 rest->magic = 0;
691 }
692
693 /* If we just got rid of the first mark, clear the thread ID */
694 if( (nssArenaMark *)NULL == arena->first_mark ) {
695 arena->marking_thread = (PRThread *)NULL;
696 }
697 }
698 #endif /* ARENA_THREADMARK */
699
700 if( release ) {
701 #ifdef ARENA_DESTRUCTOR_LIST
702 if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) {
703 arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL;
704 }
705 arena->last_destructor = arenaMark->prev_destructor;
706
707 /* Note that the arena is locked at this time */
708 nss_arena_call_destructor_chain(arenaMark->next_destructor);
709 #endif /* ARENA_DESTRUCTOR_LIST */
710
711 PR_ARENA_RELEASE(&arena->pool, inner_mark);
712 /* No error return */
713 }
714
715 PR_Unlock(arena->lock);
716 return PR_SUCCESS;
717 }
718
719 /*
720 * nssArena_Release
721 *
722 * This routine invalidates and releases all memory allocated from
723 * the specified arena after the point at which the specified mark
724 * was obtained. This routine returns a PRStatus value; if successful,
725 * it will return PR_SUCCESS. If unsuccessful, it will set an error
726 * on the error stack and return PR_FAILURE.
727 *
728 * The error may be one of the following values:
729 * NSS_ERROR_INVALID_ARENA
730 * NSS_ERROR_INVALID_ARENA_MARK
731 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
732 *
733 * Return value:
734 * PR_SUCCESS
735 * PR_FAILURE
736 */
737
738 NSS_IMPLEMENT PRStatus
739 nssArena_Release
740 (
741 NSSArena *arena,
742 nssArenaMark *arenaMark
743 )
744 {
745 return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
746 }
747
748 /*
749 * nssArena_Unmark
750 *
751 * This routine "commits" the indicated mark and any marks after
752 * it, making them unreleasable. Note that any earlier marks can
753 * still be released, and such a release will invalidate these
754 * later unmarked regions. If an arena is to be safely shared by
755 * more than one thread, all marks must be either released or
756 * unmarked. This routine returns a PRStatus value; if successful,
757 * it will return PR_SUCCESS. If unsuccessful, it will set an error
758 * on the error stack and return PR_FAILURE.
759 *
760 * The error may be one of the following values:
761 * NSS_ERROR_INVALID_ARENA
762 * NSS_ERROR_INVALID_ARENA_MARK
763 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
764 *
765 * Return value:
766 * PR_SUCCESS
767 * PR_FAILURE
768 */
769
770 NSS_IMPLEMENT PRStatus
771 nssArena_Unmark
772 (
773 NSSArena *arena,
774 nssArenaMark *arenaMark
775 )
776 {
777 return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
778 }
779
780 /*
781 * We prefix this header to all allocated blocks. It is a multiple
782 * of the alignment size. Note that this usage of a header may make
783 * purify spew bogus warnings about "potentially leaked blocks" of
784 * memory; if that gets too annoying we can add in a pointer to the
785 * header in the header itself. There's not a lot of safety here;
786 * maybe we should add a magic value?
787 */
788 struct pointer_header {
789 NSSArena *arena;
790 PRUint32 size;
791 };
792
793 static void *
794 nss_zalloc_arena_locked
795 (
796 NSSArena *arena,
797 PRUint32 size
798 )
799 {
800 void *p;
801 void *rv;
802 struct pointer_header *h;
803 PRUint32 my_size = size + sizeof(struct pointer_header);
804 PR_ARENA_ALLOCATE(p, &arena->pool, my_size);
805 if( (void *)NULL == p ) {
806 nss_SetError(NSS_ERROR_NO_MEMORY);
807 return (void *)NULL;
808 }
809 /*
810 * Do this before we unlock. This way if the user is using
811 * an arena in one thread while destroying it in another, he'll
812 * fault/FMR in his code, not ours.
813 */
814 h = (struct pointer_header *)p;
815 h->arena = arena;
816 h->size = size;
817 rv = (void *)((char *)h + sizeof(struct pointer_header));
818 (void)nsslibc_memset(rv, 0, size);
819 return rv;
820 }
821
822 /*
823 * NSS_ZAlloc
824 *
825 * This routine allocates and zeroes a section of memory of the
826 * size, and returns to the caller a pointer to that memory. If
827 * the optional arena argument is non-null, the memory will be
828 * obtained from that arena; otherwise, the memory will be obtained
829 * from the heap. This routine may return NULL upon error, in
830 * which case it will have set an error upon the error stack. The
831 * value specified for size may be zero; in which case a valid
832 * zero-length block of memory will be allocated. This block may
833 * be expanded by calling NSS_ZRealloc.
834 *
835 * The error may be one of the following values:
836 * NSS_ERROR_INVALID_ARENA
837 * NSS_ERROR_NO_MEMORY
838 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
839 *
840 * Return value:
841 * NULL upon error
842 * A pointer to the new segment of zeroed memory
843 */
844
845 NSS_IMPLEMENT void *
846 NSS_ZAlloc
847 (
848 NSSArena *arenaOpt,
849 PRUint32 size
850 )
851 {
852 return nss_ZAlloc(arenaOpt, size);
853 }
854
855 /*
856 * nss_ZAlloc
857 *
858 * This routine allocates and zeroes a section of memory of the
859 * size, and returns to the caller a pointer to that memory. If
860 * the optional arena argument is non-null, the memory will be
861 * obtained from that arena; otherwise, the memory will be obtained
862 * from the heap. This routine may return NULL upon error, in
863 * which case it will have set an error upon the error stack. The
864 * value specified for size may be zero; in which case a valid
865 * zero-length block of memory will be allocated. This block may
866 * be expanded by calling nss_ZRealloc.
867 *
868 * The error may be one of the following values:
869 * NSS_ERROR_INVALID_ARENA
870 * NSS_ERROR_NO_MEMORY
871 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
872 *
873 * Return value:
874 * NULL upon error
875 * A pointer to the new segment of zeroed memory
876 */
877
878 NSS_IMPLEMENT void *
879 nss_ZAlloc
880 (
881 NSSArena *arenaOpt,
882 PRUint32 size
883 )
884 {
885 struct pointer_header *h;
886 PRUint32 my_size = size + sizeof(struct pointer_header);
887
888 if( my_size < sizeof(struct pointer_header) ) {
889 /* Wrapped */
890 nss_SetError(NSS_ERROR_NO_MEMORY);
891 return (void *)NULL;
892 }
893
894 if( (NSSArena *)NULL == arenaOpt ) {
895 /* Heap allocation, no locking required. */
896 h = (struct pointer_header *)PR_Calloc(1, my_size);
897 if( (struct pointer_header *)NULL == h ) {
898 nss_SetError(NSS_ERROR_NO_MEMORY);
899 return (void *)NULL;
900 }
901
902 h->arena = (NSSArena *)NULL;
903 h->size = size;
904 /* We used calloc: it's already zeroed */
905
906 return (void *)((char *)h + sizeof(struct pointer_header));
907 } else {
908 void *rv;
909 /* Arena allocation */
910 #ifdef NSSDEBUG
911 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
912 return (void *)NULL;
913 }
914 #endif /* NSSDEBUG */
915
916 if( (PRLock *)NULL == arenaOpt->lock ) {
917 /* Just got destroyed */
918 nss_SetError(NSS_ERROR_INVALID_ARENA);
919 return (void *)NULL;
920 }
921 PR_Lock(arenaOpt->lock);
922
923 #ifdef ARENA_THREADMARK
924 if( (PRThread *)NULL != arenaOpt->marking_thread ) {
925 if( PR_GetCurrentThread() != arenaOpt->marking_thread ) {
926 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
927 PR_Unlock(arenaOpt->lock);
928 return (void *)NULL;
929 }
930 }
931 #endif /* ARENA_THREADMARK */
932
933 rv = nss_zalloc_arena_locked(arenaOpt, size);
934
935 PR_Unlock(arenaOpt->lock);
936 return rv;
937 }
938 /*NOTREACHED*/
939 }
940
941 /*
942 * NSS_ZFreeIf
943 *
944 * If the specified pointer is non-null, then the region of memory
945 * to which it points -- which must have been allocated with
946 * NSS_ZAlloc -- will be zeroed and released. This routine
947 * returns a PRStatus value; if successful, it will return PR_SUCCESS.
948 * If unsuccessful, it will set an error on the error stack and return
949 * PR_FAILURE.
950 *
951 * The error may be one of the following values:
952 * NSS_ERROR_INVALID_POINTER
953 *
954 * Return value:
955 * PR_SUCCESS
956 * PR_FAILURE
957 */
958 NSS_IMPLEMENT PRStatus
959 NSS_ZFreeIf
960 (
961 void *pointer
962 )
963 {
964 return nss_ZFreeIf(pointer);
965 }
966
967 /*
968 * nss_ZFreeIf
969 *
970 * If the specified pointer is non-null, then the region of memory
971 * to which it points -- which must have been allocated with
972 * nss_ZAlloc -- will be zeroed and released. This routine
973 * returns a PRStatus value; if successful, it will return PR_SUCCESS.
974 * If unsuccessful, it will set an error on the error stack and return
975 * PR_FAILURE.
976 *
977 * The error may be one of the following values:
978 * NSS_ERROR_INVALID_POINTER
979 *
980 * Return value:
981 * PR_SUCCESS
982 * PR_FAILURE
983 */
984
985 NSS_IMPLEMENT PRStatus
986 nss_ZFreeIf
987 (
988 void *pointer
989 )
990 {
991 struct pointer_header *h;
992
993 if( (void *)NULL == pointer ) {
994 return PR_SUCCESS;
995 }
996
997 h = (struct pointer_header *)((char *)pointer
998 - sizeof(struct pointer_header));
999
1000 /* Check any magic here */
1001
1002 if( (NSSArena *)NULL == h->arena ) {
1003 /* Heap */
1004 (void)nsslibc_memset(pointer, 0, h->size);
1005 PR_Free(h);
1006 return PR_SUCCESS;
1007 } else {
1008 /* Arena */
1009 #ifdef NSSDEBUG
1010 if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
1011 return PR_FAILURE;
1012 }
1013 #endif /* NSSDEBUG */
1014
1015 if( (PRLock *)NULL == h->arena->lock ) {
1016 /* Just got destroyed.. so this pointer is invalid */
1017 nss_SetError(NSS_ERROR_INVALID_POINTER);
1018 return PR_FAILURE;
1019 }
1020 PR_Lock(h->arena->lock);
1021
1022 (void)nsslibc_memset(pointer, 0, h->size);
1023
1024 /* No way to "free" it within an NSPR arena. */
1025
1026 PR_Unlock(h->arena->lock);
1027 return PR_SUCCESS;
1028 }
1029 /*NOTREACHED*/
1030 }
1031
1032 /*
1033 * NSS_ZRealloc
1034 *
1035 * This routine reallocates a block of memory obtained by calling
1036 * nss_ZAlloc or nss_ZRealloc. The portion of memory
1037 * between the new and old sizes -- which is either being newly
1038 * obtained or released -- is in either case zeroed. This routine
1039 * may return NULL upon failure, in which case it will have placed
1040 * an error on the error stack.
1041 *
1042 * The error may be one of the following values:
1043 * NSS_ERROR_INVALID_POINTER
1044 * NSS_ERROR_NO_MEMORY
1045 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
1046 *
1047 * Return value:
1048 * NULL upon error
1049 * A pointer to the replacement segment of memory
1050 */
1051
1052 NSS_EXTERN void *
1053 NSS_ZRealloc
1054 (
1055 void *pointer,
1056 PRUint32 newSize
1057 )
1058 {
1059 return nss_ZRealloc(pointer, newSize);
1060 }
1061
1062 /*
1063 * nss_ZRealloc
1064 *
1065 * This routine reallocates a block of memory obtained by calling
1066 * nss_ZAlloc or nss_ZRealloc. The portion of memory
1067 * between the new and old sizes -- which is either being newly
1068 * obtained or released -- is in either case zeroed. This routine
1069 * may return NULL upon failure, in which case it will have placed
1070 * an error on the error stack.
1071 *
1072 * The error may be one of the following values:
1073 * NSS_ERROR_INVALID_POINTER
1074 * NSS_ERROR_NO_MEMORY
1075 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
1076 *
1077 * Return value:
1078 * NULL upon error
1079 * A pointer to the replacement segment of memory
1080 */
1081
1082 NSS_EXTERN void *
1083 nss_ZRealloc
1084 (
1085 void *pointer,
1086 PRUint32 newSize
1087 )
1088 {
1089 NSSArena *arena;
1090 struct pointer_header *h, *new_h;
1091 PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
1092 void *rv;
1093
1094 if( my_newSize < sizeof(struct pointer_header) ) {
1095 /* Wrapped */
1096 nss_SetError(NSS_ERROR_NO_MEMORY);
1097 return (void *)NULL;
1098 }
1099
1100 if( (void *)NULL == pointer ) {
1101 nss_SetError(NSS_ERROR_INVALID_POINTER);
1102 return (void *)NULL;
1103 }
1104
1105 h = (struct pointer_header *)((char *)pointer
1106 - sizeof(struct pointer_header));
1107
1108 /* Check any magic here */
1109
1110 if( newSize == h->size ) {
1111 /* saves thrashing */
1112 return pointer;
1113 }
1114
1115 arena = h->arena;
1116 if (!arena) {
1117 /* Heap */
1118 new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
1119 if( (struct pointer_header *)NULL == new_h ) {
1120 nss_SetError(NSS_ERROR_NO_MEMORY);
1121 return (void *)NULL;
1122 }
1123
1124 new_h->arena = (NSSArena *)NULL;
1125 new_h->size = newSize;
1126 rv = (void *)((char *)new_h + sizeof(struct pointer_header));
1127
1128 if( newSize > h->size ) {
1129 (void)nsslibc_memcpy(rv, pointer, h->size);
1130 (void)nsslibc_memset(&((char *)rv)[ h->size ],
1131 0, (newSize - h->size));
1132 } else {
1133 (void)nsslibc_memcpy(rv, pointer, newSize);
1134 }
1135
1136 (void)nsslibc_memset(pointer, 0, h->size);
1137 h->size = 0;
1138 PR_Free(h);
1139
1140 return rv;
1141 } else {
1142 void *p;
1143 /* Arena */
1144 #ifdef NSSDEBUG
1145 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
1146 return (void *)NULL;
1147 }
1148 #endif /* NSSDEBUG */
1149
1150 if (!arena->lock) {
1151 /* Just got destroyed.. so this pointer is invalid */
1152 nss_SetError(NSS_ERROR_INVALID_POINTER);
1153 return (void *)NULL;
1154 }
1155 PR_Lock(arena->lock);
1156
1157 #ifdef ARENA_THREADMARK
1158 if (arena->marking_thread) {
1159 if (PR_GetCurrentThread() != arena->marking_thread) {
1160 PR_Unlock(arena->lock);
1161 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
1162 return (void *)NULL;
1163 }
1164 }
1165 #endif /* ARENA_THREADMARK */
1166
1167 if( newSize < h->size ) {
1168 /*
1169 * We have no general way of returning memory to the arena
1170 * (mark/release doesn't work because things may have been
1171 * allocated after this object), so the memory is gone
1172 * anyway. We might as well just return the same pointer to
1173 * the user, saying "yeah, uh-hunh, you can only use less of
1174 * it now." We'll zero the leftover part, of course. And
1175 * in fact we might as well *not* adjust h->size-- this way,
1176 * if the user reallocs back up to something not greater than
1177 * the original size, then voila, there's the memory! This
1178 * way a thrash big/small/big/small doesn't burn up the arena.
1179 */
1180 char *extra = &((char *)pointer)[ newSize ];
1181 (void)nsslibc_memset(extra, 0, (h->size - newSize));
1182 PR_Unlock(arena->lock);
1183 return pointer;
1184 }
1185
1186 PR_ARENA_ALLOCATE(p, &arena->pool, my_newSize);
1187 if( (void *)NULL == p ) {
1188 PR_Unlock(arena->lock);
1189 nss_SetError(NSS_ERROR_NO_MEMORY);
1190 return (void *)NULL;
1191 }
1192
1193 new_h = (struct pointer_header *)p;
1194 new_h->arena = arena;
1195 new_h->size = newSize;
1196 rv = (void *)((char *)new_h + sizeof(struct pointer_header));
1197 if (rv != pointer) {
1198 (void)nsslibc_memcpy(rv, pointer, h->size);
1199 (void)nsslibc_memset(pointer, 0, h->size);
1200 }
1201 (void)nsslibc_memset(&((char *)rv)[ h->size ], 0, (newSize - h->size));
1202 h->arena = (NSSArena *)NULL;
1203 h->size = 0;
1204 PR_Unlock(arena->lock);
1205 return rv;
1206 }
1207 /*NOTREACHED*/
1208 }
1209
1210 PRStatus
1211 nssArena_Shutdown(void)
1212 {
1213 PRStatus rv = PR_SUCCESS;
1214 #ifdef DEBUG
1215 rv = nssPointerTracker_finalize(&arena_pointer_tracker);
1216 #endif
1217 return rv;
1218 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/exports_win.def ('k') | mozilla/security/nss/lib/base/base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698