security/nss/lib/base/arena.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/base/arena.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1214 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * arena.c
    1.10 + *
    1.11 + * This contains the implementation of NSS's thread-safe arenas.
    1.12 + */
    1.13 +
    1.14 +#ifndef BASE_H
    1.15 +#include "base.h"
    1.16 +#endif /* BASE_H */
    1.17 +
    1.18 +#ifdef ARENA_THREADMARK
    1.19 +#include "prthread.h"
    1.20 +#endif /* ARENA_THREADMARK */
    1.21 +
    1.22 +#include "prlock.h"
    1.23 +#include "plarena.h"
    1.24 +
    1.25 +#include <string.h>
    1.26 +
    1.27 +/*
    1.28 + * NSSArena
    1.29 + *
    1.30 + * This is based on NSPR's arena code, but it is threadsafe.
    1.31 + *
    1.32 + * The public methods relating to this type are:
    1.33 + *
    1.34 + *  NSSArena_Create  -- constructor
    1.35 + *  NSSArena_Destroy
    1.36 + *  NSS_ZAlloc
    1.37 + *  NSS_ZRealloc
    1.38 + *  NSS_ZFreeIf
    1.39 + *
    1.40 + * The nonpublic methods relating to this type are:
    1.41 + *
    1.42 + *  nssArena_Create  -- constructor
    1.43 + *  nssArena_Destroy
    1.44 + *  nssArena_Mark
    1.45 + *  nssArena_Release
    1.46 + *  nssArena_Unmark
    1.47 + * 
    1.48 + *  nss_ZAlloc
    1.49 + *  nss_ZFreeIf
    1.50 + *  nss_ZRealloc
    1.51 + *
    1.52 + * In debug builds, the following calls are available:
    1.53 + *
    1.54 + *  nssArena_verifyPointer
    1.55 + *  nssArena_registerDestructor
    1.56 + *  nssArena_deregisterDestructor
    1.57 + */
    1.58 +
    1.59 +struct NSSArenaStr {
    1.60 +  PLArenaPool pool;
    1.61 +  PRLock *lock;
    1.62 +#ifdef ARENA_THREADMARK
    1.63 +  PRThread *marking_thread;
    1.64 +  nssArenaMark *first_mark;
    1.65 +  nssArenaMark *last_mark;
    1.66 +#endif /* ARENA_THREADMARK */
    1.67 +#ifdef ARENA_DESTRUCTOR_LIST
    1.68 +  struct arena_destructor_node *first_destructor;
    1.69 +  struct arena_destructor_node *last_destructor;
    1.70 +#endif /* ARENA_DESTRUCTOR_LIST */
    1.71 +};
    1.72 +
    1.73 +/*
    1.74 + * nssArenaMark
    1.75 + *
    1.76 + * This type is used to mark the current state of an NSSArena.
    1.77 + */
    1.78 +
    1.79 +struct nssArenaMarkStr {
    1.80 +  PRUint32 magic;
    1.81 +  void *mark;
    1.82 +#ifdef ARENA_THREADMARK
    1.83 +  nssArenaMark *next;
    1.84 +#endif /* ARENA_THREADMARK */
    1.85 +#ifdef ARENA_DESTRUCTOR_LIST
    1.86 +  struct arena_destructor_node *next_destructor;
    1.87 +  struct arena_destructor_node *prev_destructor;
    1.88 +#endif /* ARENA_DESTRUCTOR_LIST */
    1.89 +};
    1.90 +
    1.91 +#define MARK_MAGIC 0x4d41524b /* "MARK" how original */
    1.92 +
    1.93 +/*
    1.94 + * But first, the pointer-tracking code
    1.95 + */
    1.96 +#ifdef DEBUG
    1.97 +extern const NSSError NSS_ERROR_INTERNAL_ERROR;
    1.98 +
    1.99 +static nssPointerTracker arena_pointer_tracker;
   1.100 +
   1.101 +static PRStatus
   1.102 +arena_add_pointer
   1.103 +(
   1.104 +  const NSSArena *arena
   1.105 +)
   1.106 +{
   1.107 +  PRStatus rv;
   1.108 +
   1.109 +  rv = nssPointerTracker_initialize(&arena_pointer_tracker);
   1.110 +  if( PR_SUCCESS != rv ) {
   1.111 +    return rv;
   1.112 +  }
   1.113 +
   1.114 +  rv = nssPointerTracker_add(&arena_pointer_tracker, arena);
   1.115 +  if( PR_SUCCESS != rv ) {
   1.116 +    NSSError e = NSS_GetError();
   1.117 +    if( NSS_ERROR_NO_MEMORY != e ) {
   1.118 +      nss_SetError(NSS_ERROR_INTERNAL_ERROR);
   1.119 +    }
   1.120 +
   1.121 +    return rv;
   1.122 +  }
   1.123 +
   1.124 +  return PR_SUCCESS;
   1.125 +}
   1.126 +
   1.127 +static PRStatus
   1.128 +arena_remove_pointer
   1.129 +(
   1.130 +  const NSSArena *arena
   1.131 +)
   1.132 +{
   1.133 +  PRStatus rv;
   1.134 +
   1.135 +  rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);
   1.136 +  if( PR_SUCCESS != rv ) {
   1.137 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR);
   1.138 +  }
   1.139 +
   1.140 +  return rv;
   1.141 +}
   1.142 +
   1.143 +/*
   1.144 + * nssArena_verifyPointer
   1.145 + *
   1.146 + * This method is only present in debug builds.
   1.147 + *
   1.148 + * If the specified pointer is a valid pointer to an NSSArena object,
   1.149 + * this routine will return PR_SUCCESS.  Otherwise, it will put an
   1.150 + * error on the error stack and return PR_FAILURE.
   1.151 + *
   1.152 + * The error may be one of the following values:
   1.153 + *  NSS_ERROR_INVALID_ARENA
   1.154 + *
   1.155 + * Return value:
   1.156 + *  PR_SUCCESS if the pointer is valid
   1.157 + *  PR_FAILURE if it isn't
   1.158 + */
   1.159 +
   1.160 +NSS_IMPLEMENT PRStatus
   1.161 +nssArena_verifyPointer
   1.162 +(
   1.163 +  const NSSArena *arena
   1.164 +)
   1.165 +{
   1.166 +  PRStatus rv;
   1.167 +
   1.168 +  rv = nssPointerTracker_initialize(&arena_pointer_tracker);
   1.169 +  if( PR_SUCCESS != rv ) {
   1.170 +    /*
   1.171 +     * This is a little disingenious.  We have to initialize the
   1.172 +     * tracker, because someone could "legitimately" try to verify
   1.173 +     * an arena pointer before one is ever created.  And this step
   1.174 +     * might fail, due to lack of memory.  But the only way that
   1.175 +     * this step can fail is if it's doing the call_once stuff,
   1.176 +     * (later calls just no-op).  And if it didn't no-op, there
   1.177 +     * aren't any valid arenas.. so the argument certainly isn't one.
   1.178 +     */
   1.179 +    nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.180 +    return PR_FAILURE;
   1.181 +  }
   1.182 +
   1.183 +  rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);
   1.184 +  if( PR_SUCCESS != rv ) {
   1.185 +    nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.186 +    return PR_FAILURE;
   1.187 +  }
   1.188 +
   1.189 +  return PR_SUCCESS;
   1.190 +}
   1.191 +#endif /* DEBUG */
   1.192 +
   1.193 +#ifdef ARENA_DESTRUCTOR_LIST
   1.194 +
   1.195 +struct arena_destructor_node {
   1.196 +  struct arena_destructor_node *next;
   1.197 +  struct arena_destructor_node *prev;
   1.198 +  void (*destructor)(void *argument);
   1.199 +  void *arg;
   1.200 +};
   1.201 +
   1.202 +/*
   1.203 + * nssArena_registerDestructor
   1.204 + *
   1.205 + * This routine stores a pointer to a callback and an arbitrary
   1.206 + * pointer-sized argument in the arena, at the current point in
   1.207 + * the mark stack.  If the arena is destroyed, or an "earlier"
   1.208 + * mark is released, then this destructor will be called at that
   1.209 + * time.  Note that the destructor will be called with the arena
   1.210 + * locked, which means the destructor may free memory in that
   1.211 + * arena, but it may not allocate or cause to be allocated any
   1.212 + * memory.  This callback facility was included to support our
   1.213 + * debug-version pointer-tracker feature; overuse runs counter to
   1.214 + * the the original intent of arenas.  This routine returns a 
   1.215 + * PRStatus value; if successful, it will return PR_SUCCESS.  If 
   1.216 + * unsuccessful, it will set an error on the error stack and 
   1.217 + * return PR_FAILURE.
   1.218 + *
   1.219 + * The error may be one of the following values:
   1.220 + *  NSS_ERROR_INVALID_ARENA
   1.221 + *  NSS_ERROR_NO_MEMORY
   1.222 + *
   1.223 + * Return value:
   1.224 + *  PR_SUCCESS
   1.225 + *  PR_FAILURE
   1.226 + */
   1.227 +
   1.228 +NSS_IMPLEMENT PRStatus
   1.229 +nssArena_registerDestructor
   1.230 +(
   1.231 +  NSSArena *arena,
   1.232 +  void (*destructor)(void *argument),
   1.233 +  void *arg
   1.234 +)
   1.235 +{
   1.236 +  struct arena_destructor_node *it;
   1.237 +
   1.238 +#ifdef NSSDEBUG
   1.239 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.240 +    return PR_FAILURE;
   1.241 +  }
   1.242 +#endif /* NSSDEBUG */
   1.243 +  
   1.244 +  it = nss_ZNEW(arena, struct arena_destructor_node);
   1.245 +  if( (struct arena_destructor_node *)NULL == it ) {
   1.246 +    return PR_FAILURE;
   1.247 +  }
   1.248 +
   1.249 +  it->prev = arena->last_destructor;
   1.250 +  arena->last_destructor->next = it;
   1.251 +  arena->last_destructor = it;
   1.252 +  it->destructor = destructor;
   1.253 +  it->arg = arg;
   1.254 +
   1.255 +  if( (nssArenaMark *)NULL != arena->last_mark ) {
   1.256 +    arena->last_mark->prev_destructor = it->prev;
   1.257 +    arena->last_mark->next_destructor = it->next;
   1.258 +  }
   1.259 +
   1.260 +  return PR_SUCCESS;
   1.261 +}
   1.262 +
   1.263 +NSS_IMPLEMENT PRStatus
   1.264 +nssArena_deregisterDestructor
   1.265 +(
   1.266 +  NSSArena *arena,
   1.267 +  void (*destructor)(void *argument),
   1.268 +  void *arg
   1.269 +)
   1.270 +{
   1.271 +  struct arena_destructor_node *it;
   1.272 +
   1.273 +#ifdef NSSDEBUG
   1.274 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.275 +    return PR_FAILURE;
   1.276 +  }
   1.277 +#endif /* NSSDEBUG */
   1.278 +
   1.279 +  for( it = arena->first_destructor; it; it = it->next ) {
   1.280 +    if( (it->destructor == destructor) && (it->arg == arg) ) {
   1.281 +      break;
   1.282 +    }
   1.283 +  }
   1.284 +
   1.285 +  if( (struct arena_destructor_node *)NULL == it ) {
   1.286 +    nss_SetError(NSS_ERROR_NOT_FOUND);
   1.287 +    return PR_FAILURE;
   1.288 +  }
   1.289 +
   1.290 +  if( it == arena->first_destructor ) {
   1.291 +    arena->first_destructor = it->next;
   1.292 +  }
   1.293 +
   1.294 +  if( it == arena->last_destructor ) {
   1.295 +    arena->last_destructor = it->prev;
   1.296 +  }
   1.297 +
   1.298 +  if( (struct arena_destructor_node *)NULL != it->prev ) {
   1.299 +    it->prev->next = it->next;
   1.300 +  }
   1.301 +
   1.302 +  if( (struct arena_destructor_node *)NULL != it->next ) {
   1.303 +    it->next->prev = it->prev;
   1.304 +  }
   1.305 +
   1.306 +  {
   1.307 +    nssArenaMark *m;
   1.308 +    for( m = arena->first_mark; m; m = m->next ) {
   1.309 +      if( m->next_destructor == it ) {
   1.310 +        m->next_destructor = it->next;
   1.311 +      }
   1.312 +      if( m->prev_destructor == it ) {
   1.313 +        m->prev_destructor = it->prev;
   1.314 +      }
   1.315 +    }
   1.316 +  }
   1.317 +
   1.318 +  nss_ZFreeIf(it);
   1.319 +  return PR_SUCCESS;
   1.320 +}
   1.321 +
   1.322 +static void
   1.323 +nss_arena_call_destructor_chain
   1.324 +(
   1.325 +  struct arena_destructor_node *it
   1.326 +)
   1.327 +{
   1.328 +  for( ; it ; it = it->next ) {
   1.329 +    (*(it->destructor))(it->arg);
   1.330 +  }
   1.331 +}
   1.332 +
   1.333 +#endif /* ARENA_DESTRUCTOR_LIST */
   1.334 +
   1.335 +/*
   1.336 + * NSSArena_Create
   1.337 + *
   1.338 + * This routine creates a new memory arena.  This routine may return
   1.339 + * NULL upon error, in which case it will have created an error stack.
   1.340 + *
   1.341 + * The top-level error may be one of the following values:
   1.342 + *  NSS_ERROR_NO_MEMORY
   1.343 + *
   1.344 + * Return value:
   1.345 + *  NULL upon error
   1.346 + *  A pointer to an NSSArena upon success
   1.347 + */
   1.348 +
   1.349 +NSS_IMPLEMENT NSSArena *
   1.350 +NSSArena_Create
   1.351 +(
   1.352 +  void
   1.353 +)
   1.354 +{
   1.355 +  nss_ClearErrorStack();
   1.356 +  return nssArena_Create();
   1.357 +}
   1.358 +
   1.359 +/*
   1.360 + * nssArena_Create
   1.361 + *
   1.362 + * This routine creates a new memory arena.  This routine may return
   1.363 + * NULL upon error, in which case it will have set an error on the 
   1.364 + * error stack.
   1.365 + *
   1.366 + * The error may be one of the following values:
   1.367 + *  NSS_ERROR_NO_MEMORY
   1.368 + *
   1.369 + * Return value:
   1.370 + *  NULL upon error
   1.371 + *  A pointer to an NSSArena upon success
   1.372 + */
   1.373 +
   1.374 +NSS_IMPLEMENT NSSArena *
   1.375 +nssArena_Create
   1.376 +(
   1.377 +  void
   1.378 +)
   1.379 +{
   1.380 +  NSSArena *rv = (NSSArena *)NULL;
   1.381 +
   1.382 +  rv = nss_ZNEW((NSSArena *)NULL, NSSArena);
   1.383 +  if( (NSSArena *)NULL == rv ) {
   1.384 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.385 +    return (NSSArena *)NULL;
   1.386 +  }
   1.387 +
   1.388 +  rv->lock = PR_NewLock();
   1.389 +  if( (PRLock *)NULL == rv->lock ) {
   1.390 +    (void)nss_ZFreeIf(rv);
   1.391 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.392 +    return (NSSArena *)NULL;
   1.393 +  }
   1.394 +
   1.395 +  /*
   1.396 +   * Arena sizes.  The current security code has 229 occurrences of
   1.397 +   * PORT_NewArena.  The default chunksizes specified break down as
   1.398 +   *
   1.399 +   *  Size    Mult.   Specified as
   1.400 +   *   512       1    512
   1.401 +   *  1024       7    1024
   1.402 +   *  2048       5    2048
   1.403 +   *  2048       5    CRMF_DEFAULT_ARENA_SIZE
   1.404 +   *  2048     190    DER_DEFAULT_CHUNKSIZE
   1.405 +   *  2048      20    SEC_ASN1_DEFAULT_ARENA_SIZE
   1.406 +   *  4096       1    4096
   1.407 +   *
   1.408 +   * Obviously this "default chunksize" flexibility isn't very 
   1.409 +   * useful to us, so I'll just pick 2048.
   1.410 +   */
   1.411 +
   1.412 +  PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));
   1.413 +
   1.414 +#ifdef DEBUG
   1.415 +  {
   1.416 +    PRStatus st;
   1.417 +    st = arena_add_pointer(rv);
   1.418 +    if( PR_SUCCESS != st ) {
   1.419 +      PL_FinishArenaPool(&rv->pool);
   1.420 +      PR_DestroyLock(rv->lock);
   1.421 +      (void)nss_ZFreeIf(rv);
   1.422 +      return (NSSArena *)NULL;
   1.423 +    }
   1.424 +  }
   1.425 +#endif /* DEBUG */
   1.426 +
   1.427 +  return rv;
   1.428 +}
   1.429 +
   1.430 +/*
   1.431 + * NSSArena_Destroy
   1.432 + *
   1.433 + * This routine will destroy the specified arena, freeing all memory
   1.434 + * allocated from it.  This routine returns a PRStatus value; if 
   1.435 + * successful, it will return PR_SUCCESS.  If unsuccessful, it will
   1.436 + * create an error stack and return PR_FAILURE.
   1.437 + *
   1.438 + * The top-level error may be one of the following values:
   1.439 + *  NSS_ERROR_INVALID_ARENA
   1.440 + *
   1.441 + * Return value:
   1.442 + *  PR_SUCCESS upon success
   1.443 + *  PR_FAILURE upon failure
   1.444 + */
   1.445 +
   1.446 +NSS_IMPLEMENT PRStatus
   1.447 +NSSArena_Destroy
   1.448 +(
   1.449 +  NSSArena *arena
   1.450 +)
   1.451 +{
   1.452 +  nss_ClearErrorStack();
   1.453 +
   1.454 +#ifdef DEBUG
   1.455 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.456 +    return PR_FAILURE;
   1.457 +  }
   1.458 +#endif /* DEBUG */
   1.459 +
   1.460 +  return nssArena_Destroy(arena);
   1.461 +}
   1.462 +
   1.463 +/*
   1.464 + * nssArena_Destroy
   1.465 + *
   1.466 + * This routine will destroy the specified arena, freeing all memory
   1.467 + * allocated from it.  This routine returns a PRStatus value; if 
   1.468 + * successful, it will return PR_SUCCESS.  If unsuccessful, it will
   1.469 + * set an error on the error stack and return PR_FAILURE.
   1.470 + *
   1.471 + * The error may be one of the following values:
   1.472 + *  NSS_ERROR_INVALID_ARENA
   1.473 + *
   1.474 + * Return value:
   1.475 + *  PR_SUCCESS
   1.476 + *  PR_FAILURE
   1.477 + */
   1.478 +
   1.479 +NSS_IMPLEMENT PRStatus
   1.480 +nssArena_Destroy
   1.481 +(
   1.482 +  NSSArena *arena
   1.483 +)
   1.484 +{
   1.485 +  PRLock *lock;
   1.486 +
   1.487 +#ifdef NSSDEBUG
   1.488 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.489 +    return PR_FAILURE;
   1.490 +  }
   1.491 +#endif /* NSSDEBUG */
   1.492 +
   1.493 +  if( (PRLock *)NULL == arena->lock ) {
   1.494 +    /* Just got destroyed */
   1.495 +    nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.496 +    return PR_FAILURE;
   1.497 +  }
   1.498 +  PR_Lock(arena->lock);
   1.499 +  
   1.500 +#ifdef DEBUG
   1.501 +  if( PR_SUCCESS != arena_remove_pointer(arena) ) {
   1.502 +    PR_Unlock(arena->lock);
   1.503 +    return PR_FAILURE;
   1.504 +  }
   1.505 +#endif /* DEBUG */
   1.506 +
   1.507 +#ifdef ARENA_DESTRUCTOR_LIST
   1.508 +  /* Note that the arena is locked at this time */
   1.509 +  nss_arena_call_destructor_chain(arena->first_destructor);
   1.510 +#endif /* ARENA_DESTRUCTOR_LIST */
   1.511 +
   1.512 +  PL_FinishArenaPool(&arena->pool);
   1.513 +  lock = arena->lock;
   1.514 +  arena->lock = (PRLock *)NULL;
   1.515 +  PR_Unlock(lock);
   1.516 +  PR_DestroyLock(lock);
   1.517 +  (void)nss_ZFreeIf(arena);
   1.518 +  return PR_SUCCESS;
   1.519 +}
   1.520 +
   1.521 +static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size);
   1.522 +
   1.523 +/*
   1.524 + * nssArena_Mark
   1.525 + *
   1.526 + * This routine "marks" the current state of an arena.  Space
   1.527 + * allocated after the arena has been marked can be freed by
   1.528 + * releasing the arena back to the mark with nssArena_Release,
   1.529 + * or committed by calling nssArena_Unmark.  When successful, 
   1.530 + * this routine returns a valid nssArenaMark pointer.  This 
   1.531 + * routine may return NULL upon error, in which case it will 
   1.532 + * have set an error on the error stack.
   1.533 + *
   1.534 + * The error may be one of the following values:
   1.535 + *  NSS_ERROR_INVALID_ARENA
   1.536 + *  NSS_ERROR_NO_MEMORY
   1.537 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
   1.538 + *
   1.539 + * Return value:
   1.540 + *  NULL upon failure
   1.541 + *  An nssArenaMark pointer upon success
   1.542 + */
   1.543 +
   1.544 +NSS_IMPLEMENT nssArenaMark *
   1.545 +nssArena_Mark
   1.546 +(
   1.547 +  NSSArena *arena
   1.548 +)
   1.549 +{
   1.550 +  nssArenaMark *rv;
   1.551 +  void *p;
   1.552 +
   1.553 +#ifdef NSSDEBUG
   1.554 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.555 +    return (nssArenaMark *)NULL;
   1.556 +  }
   1.557 +#endif /* NSSDEBUG */
   1.558 +
   1.559 +  if( (PRLock *)NULL == arena->lock ) {
   1.560 +    /* Just got destroyed */
   1.561 +    nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.562 +    return (nssArenaMark *)NULL;
   1.563 +  }
   1.564 +  PR_Lock(arena->lock);
   1.565 +
   1.566 +#ifdef ARENA_THREADMARK
   1.567 +  if( (PRThread *)NULL == arena->marking_thread ) {
   1.568 +    /* Unmarked.  Store our thread ID */
   1.569 +    arena->marking_thread = PR_GetCurrentThread();
   1.570 +    /* This call never fails. */
   1.571 +  } else {
   1.572 +    /* Marked.  Verify it's the current thread */
   1.573 +    if( PR_GetCurrentThread() != arena->marking_thread ) {
   1.574 +      PR_Unlock(arena->lock);
   1.575 +      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
   1.576 +      return (nssArenaMark *)NULL;
   1.577 +    }
   1.578 +  }
   1.579 +#endif /* ARENA_THREADMARK */
   1.580 +
   1.581 +  p = PL_ARENA_MARK(&arena->pool);
   1.582 +  /* No error possible */
   1.583 +
   1.584 +  /* Do this after the mark */
   1.585 +  rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark));
   1.586 +  if( (nssArenaMark *)NULL == rv ) {
   1.587 +    PR_Unlock(arena->lock);
   1.588 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.589 +    return (nssArenaMark *)NULL;
   1.590 +  }
   1.591 +
   1.592 +#ifdef ARENA_THREADMARK
   1.593 +  if ( (nssArenaMark *)NULL == arena->first_mark) {
   1.594 +    arena->first_mark = rv;
   1.595 +    arena->last_mark = rv;
   1.596 +  } else {
   1.597 +    arena->last_mark->next = rv;
   1.598 +    arena->last_mark = rv;
   1.599 +  }
   1.600 +#endif /* ARENA_THREADMARK */
   1.601 +
   1.602 +  rv->mark = p;
   1.603 +  rv->magic = MARK_MAGIC;
   1.604 +
   1.605 +#ifdef ARENA_DESTRUCTOR_LIST
   1.606 +  rv->prev_destructor = arena->last_destructor;
   1.607 +#endif /* ARENA_DESTRUCTOR_LIST */
   1.608 +
   1.609 +  PR_Unlock(arena->lock);
   1.610 +
   1.611 +  return rv;
   1.612 +}
   1.613 +
   1.614 +/*
   1.615 + * nss_arena_unmark_release
   1.616 + *
   1.617 + * This static routine implements the routines nssArena_Release
   1.618 + * ans nssArena_Unmark, which are almost identical.
   1.619 + */
   1.620 +
   1.621 +static PRStatus
   1.622 +nss_arena_unmark_release
   1.623 +(
   1.624 +  NSSArena *arena,
   1.625 +  nssArenaMark *arenaMark,
   1.626 +  PRBool release
   1.627 +)
   1.628 +{
   1.629 +  void *inner_mark;
   1.630 +
   1.631 +#ifdef NSSDEBUG
   1.632 +  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
   1.633 +    return PR_FAILURE;
   1.634 +  }
   1.635 +#endif /* NSSDEBUG */
   1.636 +
   1.637 +  if( MARK_MAGIC != arenaMark->magic ) {
   1.638 +    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
   1.639 +    return PR_FAILURE;
   1.640 +  }
   1.641 +
   1.642 +  if( (PRLock *)NULL == arena->lock ) {
   1.643 +    /* Just got destroyed */
   1.644 +    nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.645 +    return PR_FAILURE;
   1.646 +  }
   1.647 +  PR_Lock(arena->lock);
   1.648 +
   1.649 +#ifdef ARENA_THREADMARK
   1.650 +  if( (PRThread *)NULL != arena->marking_thread ) {
   1.651 +    if( PR_GetCurrentThread() != arena->marking_thread ) {
   1.652 +      PR_Unlock(arena->lock);
   1.653 +      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
   1.654 +      return PR_FAILURE;
   1.655 +    }
   1.656 +  }
   1.657 +#endif /* ARENA_THREADMARK */
   1.658 +
   1.659 +  if( MARK_MAGIC != arenaMark->magic ) {
   1.660 +    /* Just got released */
   1.661 +    PR_Unlock(arena->lock);
   1.662 +    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
   1.663 +    return PR_FAILURE;
   1.664 +  }
   1.665 +
   1.666 +  arenaMark->magic = 0;
   1.667 +  inner_mark = arenaMark->mark;
   1.668 +
   1.669 +#ifdef ARENA_THREADMARK
   1.670 +  {
   1.671 +    nssArenaMark **pMark = &arena->first_mark;
   1.672 +    nssArenaMark *rest;
   1.673 +    nssArenaMark *last = (nssArenaMark *)NULL;
   1.674 +
   1.675 +    /* Find this mark */
   1.676 +    while( *pMark != arenaMark ) {
   1.677 +      last = *pMark;
   1.678 +      pMark = &(*pMark)->next;
   1.679 +    }
   1.680 +
   1.681 +    /* Remember the pointer, then zero it */
   1.682 +    rest = (*pMark)->next;
   1.683 +    *pMark = (nssArenaMark *)NULL;
   1.684 +
   1.685 +    arena->last_mark = last;
   1.686 +
   1.687 +    /* Invalidate any later marks being implicitly released */
   1.688 +    for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) {
   1.689 +      rest->magic = 0;
   1.690 +    }
   1.691 +
   1.692 +    /* If we just got rid of the first mark, clear the thread ID */
   1.693 +    if( (nssArenaMark *)NULL == arena->first_mark ) {
   1.694 +      arena->marking_thread = (PRThread *)NULL;
   1.695 +    }
   1.696 +  }
   1.697 +#endif /* ARENA_THREADMARK */
   1.698 +
   1.699 +  if( release ) {
   1.700 +#ifdef ARENA_DESTRUCTOR_LIST
   1.701 +    if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) {
   1.702 +      arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL;
   1.703 +    }
   1.704 +    arena->last_destructor = arenaMark->prev_destructor;
   1.705 +
   1.706 +    /* Note that the arena is locked at this time */
   1.707 +    nss_arena_call_destructor_chain(arenaMark->next_destructor);
   1.708 +#endif /* ARENA_DESTRUCTOR_LIST */
   1.709 +
   1.710 +    PL_ARENA_RELEASE(&arena->pool, inner_mark);
   1.711 +    /* No error return */
   1.712 +  }
   1.713 +
   1.714 +  PR_Unlock(arena->lock);
   1.715 +  return PR_SUCCESS;
   1.716 +}
   1.717 +
   1.718 +/*
   1.719 + * nssArena_Release
   1.720 + *
   1.721 + * This routine invalidates and releases all memory allocated from
   1.722 + * the specified arena after the point at which the specified mark
   1.723 + * was obtained.  This routine returns a PRStatus value; if successful,
   1.724 + * it will return PR_SUCCESS.  If unsuccessful, it will set an error
   1.725 + * on the error stack and return PR_FAILURE.
   1.726 + *
   1.727 + * The error may be one of the following values:
   1.728 + *  NSS_ERROR_INVALID_ARENA
   1.729 + *  NSS_ERROR_INVALID_ARENA_MARK
   1.730 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
   1.731 + *
   1.732 + * Return value:
   1.733 + *  PR_SUCCESS
   1.734 + *  PR_FAILURE
   1.735 + */
   1.736 +
   1.737 +NSS_IMPLEMENT PRStatus
   1.738 +nssArena_Release
   1.739 +(
   1.740 +  NSSArena *arena,
   1.741 +  nssArenaMark *arenaMark
   1.742 +)
   1.743 +{
   1.744 +  return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
   1.745 +}
   1.746 +
   1.747 +/*
   1.748 + * nssArena_Unmark
   1.749 + *
   1.750 + * This routine "commits" the indicated mark and any marks after
   1.751 + * it, making them unreleasable.  Note that any earlier marks can
   1.752 + * still be released, and such a release will invalidate these
   1.753 + * later unmarked regions.  If an arena is to be safely shared by
   1.754 + * more than one thread, all marks must be either released or
   1.755 + * unmarked.  This routine returns a PRStatus value; if successful,
   1.756 + * it will return PR_SUCCESS.  If unsuccessful, it will set an error
   1.757 + * on the error stack and return PR_FAILURE.
   1.758 + *
   1.759 + * The error may be one of the following values:
   1.760 + *  NSS_ERROR_INVALID_ARENA
   1.761 + *  NSS_ERROR_INVALID_ARENA_MARK
   1.762 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
   1.763 + *
   1.764 + * Return value:
   1.765 + *  PR_SUCCESS
   1.766 + *  PR_FAILURE
   1.767 + */
   1.768 +
   1.769 +NSS_IMPLEMENT PRStatus
   1.770 +nssArena_Unmark
   1.771 +(
   1.772 +  NSSArena *arena,
   1.773 +  nssArenaMark *arenaMark
   1.774 +)
   1.775 +{
   1.776 +  return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
   1.777 +}
   1.778 +
   1.779 +/*
   1.780 + * We prefix this header to all allocated blocks.  It is a multiple
   1.781 + * of the alignment size.  Note that this usage of a header may make
   1.782 + * purify spew bogus warnings about "potentially leaked blocks" of
   1.783 + * memory; if that gets too annoying we can add in a pointer to the
   1.784 + * header in the header itself.  There's not a lot of safety here;
   1.785 + * maybe we should add a magic value?
   1.786 + */
   1.787 +struct pointer_header {
   1.788 +  NSSArena *arena;
   1.789 +  PRUint32 size;
   1.790 +};
   1.791 +
   1.792 +static void *
   1.793 +nss_zalloc_arena_locked
   1.794 +(
   1.795 +  NSSArena *arena,
   1.796 +  PRUint32 size
   1.797 +)
   1.798 +{
   1.799 +  void *p;
   1.800 +  void *rv;
   1.801 +  struct pointer_header *h;
   1.802 +  PRUint32 my_size = size + sizeof(struct pointer_header);
   1.803 +  PL_ARENA_ALLOCATE(p, &arena->pool, my_size);
   1.804 +  if( (void *)NULL == p ) {
   1.805 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.806 +    return (void *)NULL;
   1.807 +  }
   1.808 +  /* 
   1.809 +   * Do this before we unlock.  This way if the user is using
   1.810 +   * an arena in one thread while destroying it in another, he'll
   1.811 +   * fault/FMR in his code, not ours.
   1.812 +   */
   1.813 +  h = (struct pointer_header *)p;
   1.814 +  h->arena = arena;
   1.815 +  h->size = size;
   1.816 +  rv = (void *)((char *)h + sizeof(struct pointer_header));
   1.817 +  (void)nsslibc_memset(rv, 0, size);
   1.818 +  return rv;
   1.819 +}
   1.820 +
   1.821 +/*
   1.822 + * NSS_ZAlloc
   1.823 + *
   1.824 + * This routine allocates and zeroes a section of memory of the 
   1.825 + * size, and returns to the caller a pointer to that memory.  If
   1.826 + * the optional arena argument is non-null, the memory will be
   1.827 + * obtained from that arena; otherwise, the memory will be obtained
   1.828 + * from the heap.  This routine may return NULL upon error, in
   1.829 + * which case it will have set an error upon the error stack.  The
   1.830 + * value specified for size may be zero; in which case a valid 
   1.831 + * zero-length block of memory will be allocated.  This block may
   1.832 + * be expanded by calling NSS_ZRealloc.
   1.833 + *
   1.834 + * The error may be one of the following values:
   1.835 + *  NSS_ERROR_INVALID_ARENA
   1.836 + *  NSS_ERROR_NO_MEMORY
   1.837 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
   1.838 + *
   1.839 + * Return value:
   1.840 + *  NULL upon error
   1.841 + *  A pointer to the new segment of zeroed memory
   1.842 + */
   1.843 +
   1.844 +NSS_IMPLEMENT void *
   1.845 +NSS_ZAlloc
   1.846 +(
   1.847 +  NSSArena *arenaOpt,
   1.848 +  PRUint32 size
   1.849 +)
   1.850 +{
   1.851 +  return nss_ZAlloc(arenaOpt, size);
   1.852 +}
   1.853 +
   1.854 +/*
   1.855 + * nss_ZAlloc
   1.856 + *
   1.857 + * This routine allocates and zeroes a section of memory of the 
   1.858 + * size, and returns to the caller a pointer to that memory.  If
   1.859 + * the optional arena argument is non-null, the memory will be
   1.860 + * obtained from that arena; otherwise, the memory will be obtained
   1.861 + * from the heap.  This routine may return NULL upon error, in
   1.862 + * which case it will have set an error upon the error stack.  The
   1.863 + * value specified for size may be zero; in which case a valid 
   1.864 + * zero-length block of memory will be allocated.  This block may
   1.865 + * be expanded by calling nss_ZRealloc.
   1.866 + *
   1.867 + * The error may be one of the following values:
   1.868 + *  NSS_ERROR_INVALID_ARENA
   1.869 + *  NSS_ERROR_NO_MEMORY
   1.870 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
   1.871 + *
   1.872 + * Return value:
   1.873 + *  NULL upon error
   1.874 + *  A pointer to the new segment of zeroed memory
   1.875 + */
   1.876 +
   1.877 +NSS_IMPLEMENT void *
   1.878 +nss_ZAlloc
   1.879 +(
   1.880 +  NSSArena *arenaOpt,
   1.881 +  PRUint32 size
   1.882 +)
   1.883 +{
   1.884 +  struct pointer_header *h;
   1.885 +  PRUint32 my_size = size + sizeof(struct pointer_header);
   1.886 +
   1.887 +  if( my_size < sizeof(struct pointer_header) ) {
   1.888 +    /* Wrapped */
   1.889 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.890 +    return (void *)NULL;
   1.891 +  }
   1.892 +
   1.893 +  if( (NSSArena *)NULL == arenaOpt ) {
   1.894 +    /* Heap allocation, no locking required. */
   1.895 +    h = (struct pointer_header *)PR_Calloc(1, my_size);
   1.896 +    if( (struct pointer_header *)NULL == h ) {
   1.897 +      nss_SetError(NSS_ERROR_NO_MEMORY);
   1.898 +      return (void *)NULL;
   1.899 +    }
   1.900 +
   1.901 +    h->arena = (NSSArena *)NULL;
   1.902 +    h->size = size;
   1.903 +    /* We used calloc: it's already zeroed */
   1.904 +
   1.905 +    return (void *)((char *)h + sizeof(struct pointer_header));
   1.906 +  } else {
   1.907 +    void *rv;
   1.908 +    /* Arena allocation */
   1.909 +#ifdef NSSDEBUG
   1.910 +    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
   1.911 +      return (void *)NULL;
   1.912 +    }
   1.913 +#endif /* NSSDEBUG */
   1.914 +
   1.915 +    if( (PRLock *)NULL == arenaOpt->lock ) {
   1.916 +      /* Just got destroyed */
   1.917 +      nss_SetError(NSS_ERROR_INVALID_ARENA);
   1.918 +      return (void *)NULL;
   1.919 +    }
   1.920 +    PR_Lock(arenaOpt->lock);
   1.921 +
   1.922 +#ifdef ARENA_THREADMARK
   1.923 +    if( (PRThread *)NULL != arenaOpt->marking_thread ) {
   1.924 +      if( PR_GetCurrentThread() != arenaOpt->marking_thread ) {
   1.925 +        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
   1.926 +        PR_Unlock(arenaOpt->lock);
   1.927 +        return (void *)NULL;
   1.928 +      }
   1.929 +    }
   1.930 +#endif /* ARENA_THREADMARK */
   1.931 +
   1.932 +    rv = nss_zalloc_arena_locked(arenaOpt, size);
   1.933 +
   1.934 +    PR_Unlock(arenaOpt->lock);
   1.935 +    return rv;
   1.936 +  }
   1.937 +  /*NOTREACHED*/
   1.938 +}
   1.939 +
   1.940 +/*
   1.941 + * NSS_ZFreeIf
   1.942 + *
   1.943 + * If the specified pointer is non-null, then the region of memory 
   1.944 + * to which it points -- which must have been allocated with 
   1.945 + * NSS_ZAlloc -- will be zeroed and released.  This routine 
   1.946 + * returns a PRStatus value; if successful, it will return PR_SUCCESS.
   1.947 + * If unsuccessful, it will set an error on the error stack and return 
   1.948 + * PR_FAILURE.
   1.949 + *
   1.950 + * The error may be one of the following values:
   1.951 + *  NSS_ERROR_INVALID_POINTER
   1.952 + *
   1.953 + * Return value:
   1.954 + *  PR_SUCCESS
   1.955 + *  PR_FAILURE
   1.956 + */
   1.957 +NSS_IMPLEMENT PRStatus
   1.958 +NSS_ZFreeIf
   1.959 +(
   1.960 +  void *pointer
   1.961 +)
   1.962 +{
   1.963 +   return nss_ZFreeIf(pointer);
   1.964 +}
   1.965 +
   1.966 +/*
   1.967 + * nss_ZFreeIf
   1.968 + *
   1.969 + * If the specified pointer is non-null, then the region of memory 
   1.970 + * to which it points -- which must have been allocated with 
   1.971 + * nss_ZAlloc -- will be zeroed and released.  This routine 
   1.972 + * returns a PRStatus value; if successful, it will return PR_SUCCESS.
   1.973 + * If unsuccessful, it will set an error on the error stack and return 
   1.974 + * PR_FAILURE.
   1.975 + *
   1.976 + * The error may be one of the following values:
   1.977 + *  NSS_ERROR_INVALID_POINTER
   1.978 + *
   1.979 + * Return value:
   1.980 + *  PR_SUCCESS
   1.981 + *  PR_FAILURE
   1.982 + */
   1.983 +
   1.984 +NSS_IMPLEMENT PRStatus
   1.985 +nss_ZFreeIf
   1.986 +(
   1.987 +  void *pointer
   1.988 +)
   1.989 +{
   1.990 +  struct pointer_header *h;
   1.991 +
   1.992 +  if( (void *)NULL == pointer ) {
   1.993 +    return PR_SUCCESS;
   1.994 +  }
   1.995 +
   1.996 +  h = (struct pointer_header *)((char *)pointer
   1.997 +    - sizeof(struct pointer_header));
   1.998 +
   1.999 +  /* Check any magic here */
  1.1000 +
  1.1001 +  if( (NSSArena *)NULL == h->arena ) {
  1.1002 +    /* Heap */
  1.1003 +    (void)nsslibc_memset(pointer, 0, h->size);
  1.1004 +    PR_Free(h);
  1.1005 +    return PR_SUCCESS;
  1.1006 +  } else {
  1.1007 +    /* Arena */
  1.1008 +#ifdef NSSDEBUG
  1.1009 +    if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
  1.1010 +      return PR_FAILURE;
  1.1011 +    }
  1.1012 +#endif /* NSSDEBUG */
  1.1013 +
  1.1014 +    if( (PRLock *)NULL == h->arena->lock ) {
  1.1015 +      /* Just got destroyed.. so this pointer is invalid */
  1.1016 +      nss_SetError(NSS_ERROR_INVALID_POINTER);
  1.1017 +      return PR_FAILURE;
  1.1018 +    }
  1.1019 +    PR_Lock(h->arena->lock);
  1.1020 +
  1.1021 +    (void)nsslibc_memset(pointer, 0, h->size);
  1.1022 +
  1.1023 +    /* No way to "free" it within an NSPR arena. */
  1.1024 +
  1.1025 +    PR_Unlock(h->arena->lock);
  1.1026 +    return PR_SUCCESS;
  1.1027 +  }
  1.1028 +  /*NOTREACHED*/
  1.1029 +}
  1.1030 +
  1.1031 +/*
  1.1032 + * NSS_ZRealloc
  1.1033 + *
  1.1034 + * This routine reallocates a block of memory obtained by calling
  1.1035 + * nss_ZAlloc or nss_ZRealloc.  The portion of memory 
  1.1036 + * between the new and old sizes -- which is either being newly
  1.1037 + * obtained or released -- is in either case zeroed.  This routine 
  1.1038 + * may return NULL upon failure, in which case it will have placed 
  1.1039 + * an error on the error stack.
  1.1040 + *
  1.1041 + * The error may be one of the following values:
  1.1042 + *  NSS_ERROR_INVALID_POINTER
  1.1043 + *  NSS_ERROR_NO_MEMORY
  1.1044 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  1.1045 + *
  1.1046 + * Return value:
  1.1047 + *  NULL upon error
  1.1048 + *  A pointer to the replacement segment of memory
  1.1049 + */
  1.1050 +
  1.1051 +NSS_EXTERN void *
  1.1052 +NSS_ZRealloc
  1.1053 +(
  1.1054 +  void *pointer,
  1.1055 +  PRUint32 newSize
  1.1056 +)
  1.1057 +{
  1.1058 +    return nss_ZRealloc(pointer, newSize);
  1.1059 +}
  1.1060 +
  1.1061 +/*
  1.1062 + * nss_ZRealloc
  1.1063 + *
  1.1064 + * This routine reallocates a block of memory obtained by calling
  1.1065 + * nss_ZAlloc or nss_ZRealloc.  The portion of memory 
  1.1066 + * between the new and old sizes -- which is either being newly
  1.1067 + * obtained or released -- is in either case zeroed.  This routine 
  1.1068 + * may return NULL upon failure, in which case it will have placed 
  1.1069 + * an error on the error stack.
  1.1070 + *
  1.1071 + * The error may be one of the following values:
  1.1072 + *  NSS_ERROR_INVALID_POINTER
  1.1073 + *  NSS_ERROR_NO_MEMORY
  1.1074 + *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  1.1075 + *
  1.1076 + * Return value:
  1.1077 + *  NULL upon error
  1.1078 + *  A pointer to the replacement segment of memory
  1.1079 + */
  1.1080 +
  1.1081 +NSS_EXTERN void *
  1.1082 +nss_ZRealloc
  1.1083 +(
  1.1084 +  void *pointer,
  1.1085 +  PRUint32 newSize
  1.1086 +)
  1.1087 +{
  1.1088 +  NSSArena *arena;
  1.1089 +  struct pointer_header *h, *new_h;
  1.1090 +  PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
  1.1091 +  void *rv;
  1.1092 +
  1.1093 +  if( my_newSize < sizeof(struct pointer_header) ) {
  1.1094 +    /* Wrapped */
  1.1095 +    nss_SetError(NSS_ERROR_NO_MEMORY);
  1.1096 +    return (void *)NULL;
  1.1097 +  }
  1.1098 +
  1.1099 +  if( (void *)NULL == pointer ) {
  1.1100 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
  1.1101 +    return (void *)NULL;
  1.1102 +  }
  1.1103 +
  1.1104 +  h = (struct pointer_header *)((char *)pointer
  1.1105 +    - sizeof(struct pointer_header));
  1.1106 +
  1.1107 +  /* Check any magic here */
  1.1108 +
  1.1109 +  if( newSize == h->size ) {
  1.1110 +    /* saves thrashing */
  1.1111 +    return pointer;
  1.1112 +  }
  1.1113 +
  1.1114 +  arena = h->arena;
  1.1115 +  if (!arena) {
  1.1116 +    /* Heap */
  1.1117 +    new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
  1.1118 +    if( (struct pointer_header *)NULL == new_h ) {
  1.1119 +      nss_SetError(NSS_ERROR_NO_MEMORY);
  1.1120 +      return (void *)NULL;
  1.1121 +    }
  1.1122 +
  1.1123 +    new_h->arena = (NSSArena *)NULL;
  1.1124 +    new_h->size = newSize;
  1.1125 +    rv = (void *)((char *)new_h + sizeof(struct pointer_header));
  1.1126 +
  1.1127 +    if( newSize > h->size ) {
  1.1128 +      (void)nsslibc_memcpy(rv, pointer, h->size);
  1.1129 +      (void)nsslibc_memset(&((char *)rv)[ h->size ], 
  1.1130 +                           0, (newSize - h->size));
  1.1131 +    } else {
  1.1132 +      (void)nsslibc_memcpy(rv, pointer, newSize);
  1.1133 +    }
  1.1134 +
  1.1135 +    (void)nsslibc_memset(pointer, 0, h->size);
  1.1136 +    h->size = 0;
  1.1137 +    PR_Free(h);
  1.1138 +
  1.1139 +    return rv;
  1.1140 +  } else {
  1.1141 +    void *p;
  1.1142 +    /* Arena */
  1.1143 +#ifdef NSSDEBUG
  1.1144 +    if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
  1.1145 +      return (void *)NULL;
  1.1146 +    }
  1.1147 +#endif /* NSSDEBUG */
  1.1148 +
  1.1149 +    if (!arena->lock) {
  1.1150 +      /* Just got destroyed.. so this pointer is invalid */
  1.1151 +      nss_SetError(NSS_ERROR_INVALID_POINTER);
  1.1152 +      return (void *)NULL;
  1.1153 +    }
  1.1154 +    PR_Lock(arena->lock);
  1.1155 +
  1.1156 +#ifdef ARENA_THREADMARK
  1.1157 +    if (arena->marking_thread) {
  1.1158 +      if (PR_GetCurrentThread() != arena->marking_thread) {
  1.1159 +        PR_Unlock(arena->lock);
  1.1160 +        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
  1.1161 +        return (void *)NULL;
  1.1162 +      }
  1.1163 +    }
  1.1164 +#endif /* ARENA_THREADMARK */
  1.1165 +
  1.1166 +    if( newSize < h->size ) {
  1.1167 +      /*
  1.1168 +       * We have no general way of returning memory to the arena
  1.1169 +       * (mark/release doesn't work because things may have been
  1.1170 +       * allocated after this object), so the memory is gone
  1.1171 +       * anyway.  We might as well just return the same pointer to
  1.1172 +       * the user, saying "yeah, uh-hunh, you can only use less of
  1.1173 +       * it now."  We'll zero the leftover part, of course.  And
  1.1174 +       * in fact we might as well *not* adjust h->size-- this way,
  1.1175 +       * if the user reallocs back up to something not greater than
  1.1176 +       * the original size, then voila, there's the memory!  This
  1.1177 +       * way a thrash big/small/big/small doesn't burn up the arena.
  1.1178 +       */
  1.1179 +      char *extra = &((char *)pointer)[ newSize ];
  1.1180 +      (void)nsslibc_memset(extra, 0, (h->size - newSize));
  1.1181 +      PR_Unlock(arena->lock);
  1.1182 +      return pointer;
  1.1183 +    }
  1.1184 +
  1.1185 +    PL_ARENA_ALLOCATE(p, &arena->pool, my_newSize);
  1.1186 +    if( (void *)NULL == p ) {
  1.1187 +      PR_Unlock(arena->lock);
  1.1188 +      nss_SetError(NSS_ERROR_NO_MEMORY);
  1.1189 +      return (void *)NULL;
  1.1190 +    }
  1.1191 +
  1.1192 +    new_h = (struct pointer_header *)p;
  1.1193 +    new_h->arena = arena;
  1.1194 +    new_h->size = newSize;
  1.1195 +    rv = (void *)((char *)new_h + sizeof(struct pointer_header));
  1.1196 +    if (rv != pointer) {
  1.1197 +	(void)nsslibc_memcpy(rv, pointer, h->size);
  1.1198 +	(void)nsslibc_memset(pointer, 0, h->size);
  1.1199 +    }
  1.1200 +    (void)nsslibc_memset(&((char *)rv)[ h->size ], 0, (newSize - h->size));
  1.1201 +    h->arena = (NSSArena *)NULL;
  1.1202 +    h->size = 0;
  1.1203 +    PR_Unlock(arena->lock);
  1.1204 +    return rv;
  1.1205 +  }
  1.1206 +  /*NOTREACHED*/
  1.1207 +}
  1.1208 +
  1.1209 +PRStatus 
  1.1210 +nssArena_Shutdown(void)
  1.1211 +{
  1.1212 +  PRStatus rv = PR_SUCCESS;
  1.1213 +#ifdef DEBUG
  1.1214 +  rv = nssPointerTracker_finalize(&arena_pointer_tracker);
  1.1215 +#endif
  1.1216 +  return rv;
  1.1217 +}

mercurial