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 + -
显示快捷键?