arena.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,122 行 · 第 1/2 页

C
1,122
字号
 *  NULL upon failure *  An nssArenaMark pointer upon success */NSS_IMPLEMENT nssArenaMark *nssArena_Mark(  NSSArena *arena){  nssArenaMark *rv;  void *p;#ifdef NSSDEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return (nssArenaMark *)NULL;  }#endif /* NSSDEBUG */  PR_Lock(arena->lock);  if( (PRLock *)NULL == arena->lock ) {    /* Just got destroyed */    nss_SetError(NSS_ERROR_INVALID_ARENA);    return (nssArenaMark *)NULL;  }#ifdef ARENA_THREADMARK  if( (PRThread *)NULL == arena->marking_thread ) {    /* Unmarked.  Store our thread ID */    arena->marking_thread = PR_GetCurrentThread();    /* This call never fails. */  } else {    /* Marked.  Verify it's the current thread */    if( PR_GetCurrentThread() != arena->marking_thread ) {      PR_Unlock(arena->lock);      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);      return (nssArenaMark *)NULL;    }  }#endif /* ARENA_THREADMARK */  p = PL_ARENA_MARK(&arena->pool);  /* No error possible */  /* Do this after the mark */  rv = nss_ZNEW(arena, nssArenaMark);  if( (nssArenaMark *)NULL == rv ) {    PR_Unlock(arena->lock);    nss_SetError(NSS_ERROR_NO_MEMORY);    return (nssArenaMark *)NULL;  }#ifdef ARENA_THREADMARK  arena->last_mark->next = rv;  arena->last_mark = rv;#endif /* ARENA_THREADMARK */  rv->mark = p;  rv->magic = MARK_MAGIC;#ifdef ARENA_DESTRUCTOR_LIST  rv->prev_destructor = arena->last_destructor;#endif /* ARENA_DESTRUCTOR_LIST */  PR_Unlock(arena->lock);  return rv;}/* * nss_arena_unmark_release * * This static routine implements the routines nssArena_Release * ans nssArena_Unmark, which are almost identical. */static PRStatusnss_arena_unmark_release(  NSSArena *arena,  nssArenaMark *arenaMark,  PRBool release){  void *inner_mark;#ifdef NSSDEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return PR_FAILURE;  }#endif /* NSSDEBUG */  if( MARK_MAGIC != arenaMark->magic ) {    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);    return PR_FAILURE;  }  PR_Lock(arena->lock);  if( (PRLock *)NULL == arena->lock ) {    /* Just got destroyed */    nss_SetError(NSS_ERROR_INVALID_ARENA);    return PR_FAILURE;  }#ifdef ARENA_THREADMARK  if( (PRThread *)NULL != arena->marking_thread ) {    if( PR_GetCurrentThread() != arena->marking_thread ) {      PR_Unlock(arena->lock);      nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);      return PR_FAILURE;    }  }#endif /* ARENA_THREADMARK */  if( MARK_MAGIC != arenaMark->magic ) {    /* Just got released */    PR_Unlock(arena->lock);    nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);    return PR_FAILURE;  }  arenaMark->magic = 0;  inner_mark = arenaMark->mark;#ifdef ARENA_THREADMARK  {    nssArenaMark **pMark = &arena->first_mark;    nssArenaMark *rest;    nssArenaMark *last = (nssArenaMark *)NULL;    /* Find this mark */    while( *pMark != arenaMark ) {      last = *pMark;      pMark = &(*pMark)->next;    }    /* Remember the pointer, then zero it */    rest = (*pMark)->next;    *pMark = (nssArenaMark *)NULL;    arena->last_mark = last;    /* Invalidate any later marks being implicitly released */    for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) {      rest->magic = 0;    }    /* If we just got rid of the first mark, clear the thread ID */    if( (nssArenaMark *)NULL == arena->first_mark ) {      arena->marking_thread = (PRThread *)NULL;    }  }#endif /* ARENA_THREADMARK */  if( release ) {#ifdef ARENA_DESTRUCTOR_LIST    if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) {      arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL;    }    arena->last_destructor = arenaMark->prev_destructor;    /* Note that the arena is locked at this time */    nss_arena_call_destructor_chain(arenaMark->next_destructor);#endif /* ARENA_DESTRUCTOR_LIST */    PR_ARENA_RELEASE(&arena->pool, inner_mark);    /* No error return */  }  PR_Unlock(arena->lock);  return PR_SUCCESS;}/* * nssArena_Release * * This routine invalidates and releases all memory allocated from * the specified arena after the point at which the specified mark * was obtained.  This routine returns a PRStatus value; if successful, * it will return PR_SUCCESS.  If unsuccessful, it will set an error * on the error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_ARENA *  NSS_ERROR_INVALID_ARENA_MARK *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssArena_Release(  NSSArena *arena,  nssArenaMark *arenaMark){  return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);}/* * nssArena_Unmark * * This routine "commits" the indicated mark and any marks after * it, making them unreleasable.  Note that any earlier marks can * still be released, and such a release will invalidate these * later unmarked regions.  If an arena is to be safely shared by * more than one thread, all marks must be either released or * unmarked.  This routine returns a PRStatus value; if successful, * it will return PR_SUCCESS.  If unsuccessful, it will set an error * on the error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_ARENA *  NSS_ERROR_INVALID_ARENA_MARK *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssArena_Unmark(  NSSArena *arena,  nssArenaMark *arenaMark){  return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);}/* * We prefix this header to all allocated blocks.  It is a multiple * of the alignment size.  Note that this usage of a header may make * purify spew bogus warnings about "potentially leaked blocks" of * memory; if that gets too annoying we can add in a pointer to the * header in the header itself.  There's not a lot of safety here; * maybe we should add a magic value? */struct pointer_header {  NSSArena *arena;  PRUint32 size;};/* * nss_ZAlloc * * This routine allocates and zeroes a section of memory of the  * size, and returns to the caller a pointer to that memory.  If * the optional arena argument is non-null, the memory will be * obtained from that arena; otherwise, the memory will be obtained * from the heap.  This routine may return NULL upon error, in * which case it will have set an error upon the error stack.  The * value specified for size may be zero; in which case a valid  * zero-length block of memory will be allocated.  This block may * be expanded by calling nss_ZRealloc. * * The error may be one of the following values: *  NSS_ERROR_INVALID_ARENA *  NSS_ERROR_NO_MEMORY *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD * * Return value: *  NULL upon error *  A pointer to the new segment of zeroed memory */NSS_IMPLEMENT void *nss_ZAlloc(  NSSArena *arenaOpt,  PRUint32 size){  struct pointer_header *h;  PRUint32 my_size = size + sizeof(struct pointer_header);  if( my_size < sizeof(struct pointer_header) ) {    /* Wrapped */    nss_SetError(NSS_ERROR_NO_MEMORY);    return (void *)NULL;  }  if( (NSSArena *)NULL == arenaOpt ) {    /* Heap allocation, no locking required. */    h = (struct pointer_header *)PR_Calloc(1, my_size);    if( (struct pointer_header *)NULL == h ) {      nss_SetError(NSS_ERROR_NO_MEMORY);      return (void *)NULL;    }    h->arena = (NSSArena *)NULL;    h->size = size;    /* We used calloc: it's already zeroed */    return (void *)((char *)h + sizeof(struct pointer_header));  } else {    void *p;    void *rv;    /* Arena allocation */#ifdef NSSDEBUG    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {      return (void *)NULL;    }#endif /* NSSDEBUG */    PR_Lock(arenaOpt->lock);    if( (PRLock *)NULL == arenaOpt->lock ) {      /* Just got destroyed */      nss_SetError(NSS_ERROR_INVALID_ARENA);      return (void *)NULL;    }#ifdef ARENA_THREADMARK    if( (PRThread *)NULL != arenaOpt->marking_thread ) {      if( PR_GetCurrentThread() != arenaOpt->marking_thread ) {        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);        PR_Unlock(arenaOpt->lock);        return (void *)NULL;      }    }#endif /* ARENA_THREADMARK */    PR_ARENA_ALLOCATE(p, &arenaOpt->pool, my_size);    if( (void *)NULL == p ) {      PR_Unlock(arenaOpt->lock);      nss_SetError(NSS_ERROR_NO_MEMORY);      return (void *)NULL;    }    /*      * Do this before we unlock.  This way if the user is using     * an arena in one thread while destroying it in another, he'll     * fault/FMR in his code, not ours.     */    h = (struct pointer_header *)p;    h->arena = arenaOpt;    h->size = size;    rv = (void *)((char *)h + sizeof(struct pointer_header));    (void)nsslibc_memset(rv, 0, size);    PR_Unlock(arenaOpt->lock);    return rv;  }  /*NOTREACHED*/}/* * nss_ZFreeIf * * If the specified pointer is non-null, then the region of memory  * to which it points -- which must have been allocated with  * nss_ZAlloc -- will be zeroed and released.  This routine  * returns a PRStatus value; if successful, it will return PR_SUCCESS. * If unsuccessful, it will set an error on the error stack and return  * PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnss_ZFreeIf(  void *pointer){  struct pointer_header *h;  if( (void *)NULL == pointer ) {    return PR_SUCCESS;  }  h = (struct pointer_header *)&((char *)pointer)    [ - sizeof(struct pointer_header) ];  /* Check any magic here */  if( (NSSArena *)NULL == h->arena ) {    /* Heap */    (void)nsslibc_memset(pointer, 0, h->size);    PR_Free(h);    return PR_SUCCESS;  } else {    /* Arena */#ifdef NSSDEBUG    if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {      return PR_FAILURE;    }#endif /* NSSDEBUG */    PR_Lock(h->arena->lock);    if( (PRLock *)NULL == h->arena->lock ) {      /* Just got destroyed.. so this pointer is invalid */      nss_SetError(NSS_ERROR_INVALID_POINTER);      return PR_FAILURE;    }    (void)nsslibc_memset(pointer, 0, h->size);    /* No way to "free" it within an NSPR arena. */    PR_Unlock(h->arena->lock);    return PR_SUCCESS;  }  /*NOTREACHED*/}/* * nss_ZRealloc * * This routine reallocates a block of memory obtained by calling * nss_ZAlloc or nss_ZRealloc.  The portion of memory  * between the new and old sizes -- which is either being newly * obtained or released -- is in either case zeroed.  This routine  * may return NULL upon failure, in which case it will have placed  * an error on the error stack. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER *  NSS_ERROR_NO_MEMORY *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD * * Return value: *  NULL upon error *  A pointer to the replacement segment of memory */NSS_EXTERN void *nss_ZRealloc(  void *pointer,  PRUint32 newSize){  struct pointer_header *h, *new_h;  PRUint32 my_newSize = newSize + sizeof(struct pointer_header);  void *rv;  if( my_newSize < sizeof(struct pointer_header) ) {    /* Wrapped */    nss_SetError(NSS_ERROR_NO_MEMORY);    return (void *)NULL;  }  if( (void *)NULL == pointer ) {    nss_SetError(NSS_ERROR_INVALID_POINTER);    return (void *)NULL;  }  h = (struct pointer_header *)&((char *)pointer)    [ - sizeof(struct pointer_header) ];  /* Check any magic here */  if( newSize == h->size ) {    /* saves thrashing */    return pointer;  }  if( (NSSArena *)NULL == h->arena ) {    /* Heap */    new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);    if( (struct pointer_header *)NULL == new_h ) {      nss_SetError(NSS_ERROR_NO_MEMORY);      return (void *)NULL;    }    new_h->arena = (NSSArena *)NULL;    new_h->size = newSize;    rv = (void *)((char *)new_h + sizeof(struct pointer_header));    if( newSize > h->size ) {      (void)nsslibc_memcpy(rv, pointer, h->size);      (void)nsslibc_memset(&((char *)rv)[ h->size ],                            0, (newSize - h->size));    } else {      (void)nsslibc_memcpy(rv, pointer, newSize);    }    (void)nsslibc_memset(pointer, 0, h->size);    h->size = 0;    PR_Free(h);    return rv;  } else {    void *p;    /* Arena */#ifdef NSSDEBUG    if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {      return (void *)NULL;    }#endif /* NSSDEBUG */    PR_Lock(h->arena->lock);    if( (PRLock *)NULL == h->arena->lock ) {      /* Just got destroyed.. so this pointer is invalid */      nss_SetError(NSS_ERROR_INVALID_POINTER);      return (void *)NULL;    }#ifdef ARENA_THREADMARK    if( (PRThread *)NULL != h->arena->marking_thread ) {      if( PR_GetCurrentThread() != h->arena->marking_thread ) {        PR_Unlock(h->arena->lock);        nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);        return (void *)NULL;      }    }#endif /* ARENA_THREADMARK */    if( newSize < h->size ) {      /*       * We have no general way of returning memory to the arena       * (mark/release doesn't work because things may have been       * allocated after this object), so the memory is gone       * anyway.  We might as well just return the same pointer to       * the user, saying "yeah, uh-hunh, you can only use less of       * it now."  We'll zero the leftover part, of course.  And       * in fact we might as well *not* adjust h->size-- this way,       * if the user reallocs back up to something not greater than       * the original size, then voila, there's the memory!  This       * way a thrash big/small/big/small doesn't burn up the arena.       */      char *extra = &((char *)pointer)[ newSize ];      (void)nsslibc_memset(extra, 0, (h->size - newSize));      PR_Unlock(h->arena->lock);      return pointer;    }    PR_ARENA_ALLOCATE(p, &h->arena->pool, my_newSize);    if( (void *)NULL == p ) {      PR_Unlock(h->arena->lock);      nss_SetError(NSS_ERROR_NO_MEMORY);      return (void *)NULL;    }    new_h = (struct pointer_header *)p;    new_h->arena = h->arena;    new_h->size = newSize;    rv = (void *)((char *)h + sizeof(struct pointer_header));    (void)nsslibc_memcpy(rv, pointer, h->size);    (void)nsslibc_memset(&((char *)rv)[ h->size ], 0,                          (newSize - h->size));    (void)nsslibc_memset(pointer, 0, h->size);    h->arena = (NSSArena *)NULL;    h->size = 0;    PR_Unlock(h->arena->lock);    return rv;  }  /*NOTREACHED*/}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?