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