2008-06-06 05:40:11 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Netscape security libraries.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2008-08-14 21:12:54 -07:00
|
|
|
static const char CVS_ID[] = "@(#) $RCSfile: error.c,v $ $Revision: 1.9 $ $Date: 2008/05/17 03:44:39 $";
|
2008-06-06 05:40:11 -07:00
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* error.c
|
|
|
|
*
|
|
|
|
* This file contains the code implementing the per-thread error
|
|
|
|
* stacks upon which most NSS routines report their errors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef BASE_H
|
|
|
|
#include "base.h"
|
|
|
|
#endif /* BASE_H */
|
2008-08-14 21:12:54 -07:00
|
|
|
#include <limits.h> /* for UINT_MAX */
|
2008-06-06 05:40:11 -07:00
|
|
|
#include <string.h> /* for memmove */
|
|
|
|
|
|
|
|
#define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The stack itself has a header, and a sequence of integers.
|
|
|
|
* The header records the amount of space (as measured in stack
|
|
|
|
* slots) already allocated for the stack, and the count of the
|
|
|
|
* number of records currently being used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct stack_header_str {
|
|
|
|
PRUint16 space;
|
|
|
|
PRUint16 count;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct error_stack_str {
|
|
|
|
struct stack_header_str header;
|
|
|
|
PRInt32 stack[1];
|
|
|
|
};
|
|
|
|
typedef struct error_stack_str error_stack;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* error_stack_index
|
|
|
|
*
|
|
|
|
* Thread-private data must be indexed. This is that index.
|
|
|
|
* See PR_NewThreadPrivateIndex for more information.
|
2008-08-14 21:12:54 -07:00
|
|
|
*
|
|
|
|
* Thread-private data indexes are in the range [0, 127].
|
2008-06-06 05:40:11 -07:00
|
|
|
*/
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
#define INVALID_TPD_INDEX UINT_MAX
|
|
|
|
static PRUintn error_stack_index = INVALID_TPD_INDEX;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call_once
|
|
|
|
*
|
|
|
|
* The thread-private index must be obtained (once!) at runtime.
|
|
|
|
* This block is used for that one-time call.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static PRCallOnceType error_call_once;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* error_once_function
|
|
|
|
*
|
|
|
|
* This is the once-called callback.
|
|
|
|
*/
|
|
|
|
static PRStatus
|
|
|
|
error_once_function ( void)
|
|
|
|
{
|
|
|
|
return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* error_get_my_stack
|
|
|
|
*
|
|
|
|
* This routine returns the calling thread's error stack, creating
|
|
|
|
* it if necessary. It may return NULL upon error, which implicitly
|
|
|
|
* means that it ran out of memory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static error_stack *
|
|
|
|
error_get_my_stack ( void)
|
|
|
|
{
|
|
|
|
PRStatus st;
|
|
|
|
error_stack *rv;
|
|
|
|
PRUintn new_size;
|
|
|
|
PRUint32 new_bytes;
|
|
|
|
error_stack *new_stack;
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
if( INVALID_TPD_INDEX == error_stack_index ) {
|
2008-06-06 05:40:11 -07:00
|
|
|
st = PR_CallOnce(&error_call_once, error_once_function);
|
|
|
|
if( PR_SUCCESS != st ) {
|
|
|
|
return (error_stack *)NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (error_stack *)PR_GetThreadPrivate(error_stack_index);
|
|
|
|
if( (error_stack *)NULL == rv ) {
|
|
|
|
/* Doesn't exist; create one */
|
|
|
|
new_size = 16;
|
|
|
|
} else if( rv->header.count == rv->header.space &&
|
|
|
|
rv->header.count < NSS_MAX_ERROR_STACK_COUNT ) {
|
|
|
|
/* Too small, expand it */
|
|
|
|
new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
|
|
|
|
} else {
|
|
|
|
/* Okay, return it */
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
|
|
|
|
/* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
|
|
|
|
new_stack = PR_Calloc(1, new_bytes);
|
|
|
|
|
|
|
|
if( (error_stack *)NULL != new_stack ) {
|
|
|
|
if( (error_stack *)NULL != rv ) {
|
|
|
|
(void)nsslibc_memcpy(new_stack,rv,rv->header.space);
|
|
|
|
}
|
|
|
|
new_stack->header.space = new_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the value, whether or not the allocation worked */
|
|
|
|
PR_SetThreadPrivate(error_stack_index, new_stack);
|
|
|
|
return new_stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The error stack
|
|
|
|
*
|
|
|
|
* The public methods relating to the error stack are:
|
|
|
|
*
|
|
|
|
* NSS_GetError
|
|
|
|
* NSS_GetErrorStack
|
|
|
|
*
|
|
|
|
* The nonpublic methods relating to the error stack are:
|
|
|
|
*
|
|
|
|
* nss_SetError
|
|
|
|
* nss_ClearErrorStack
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NSS_GetError
|
|
|
|
*
|
|
|
|
* This routine returns the highest-level (most general) error set
|
|
|
|
* by the most recent NSS library routine called by the same thread
|
|
|
|
* calling this routine.
|
|
|
|
*
|
|
|
|
* This routine cannot fail. However, it may return zero, which
|
|
|
|
* indicates that the previous NSS library call did not set an error.
|
|
|
|
*
|
|
|
|
* Return value:
|
|
|
|
* 0 if no error has been set
|
|
|
|
* A nonzero error number
|
|
|
|
*/
|
|
|
|
|
|
|
|
NSS_IMPLEMENT PRInt32
|
|
|
|
NSS_GetError ( void)
|
|
|
|
{
|
|
|
|
error_stack *es = error_get_my_stack();
|
|
|
|
|
|
|
|
if( (error_stack *)NULL == es ) {
|
|
|
|
return NSS_ERROR_NO_MEMORY; /* Good guess! */
|
|
|
|
}
|
|
|
|
|
|
|
|
if( 0 == es->header.count ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return es->stack[ es->header.count-1 ];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NSS_GetErrorStack
|
|
|
|
*
|
|
|
|
* This routine returns a pointer to an array of integers, containing
|
|
|
|
* the entire sequence or "stack" of errors set by the most recent NSS
|
|
|
|
* library routine called by the same thread calling this routine.
|
|
|
|
* NOTE: the caller DOES NOT OWN the memory pointed to by the return
|
|
|
|
* value. The pointer will remain valid until the calling thread
|
|
|
|
* calls another NSS routine. The lowest-level (most specific) error
|
|
|
|
* is first in the array, and the highest-level is last. The array is
|
|
|
|
* zero-terminated. This routine may return NULL upon error; this
|
|
|
|
* indicates a low-memory situation.
|
|
|
|
*
|
|
|
|
* Return value:
|
|
|
|
* NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
|
|
|
|
* A NON-caller-owned pointer to an array of integers
|
|
|
|
*/
|
|
|
|
|
|
|
|
NSS_IMPLEMENT PRInt32 *
|
|
|
|
NSS_GetErrorStack ( void)
|
|
|
|
{
|
|
|
|
error_stack *es = error_get_my_stack();
|
|
|
|
|
|
|
|
if( (error_stack *)NULL == es ) {
|
|
|
|
return (PRInt32 *)NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure it's terminated */
|
|
|
|
es->stack[ es->header.count ] = 0;
|
|
|
|
|
|
|
|
return es->stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nss_SetError
|
|
|
|
*
|
|
|
|
* This routine places a new error code on the top of the calling
|
|
|
|
* thread's error stack. Calling this routine wiht an error code
|
|
|
|
* of zero will clear the error stack.
|
|
|
|
*/
|
|
|
|
|
|
|
|
NSS_IMPLEMENT void
|
|
|
|
nss_SetError ( PRUint32 error)
|
|
|
|
{
|
|
|
|
error_stack *es;
|
|
|
|
|
|
|
|
if( 0 == error ) {
|
|
|
|
nss_ClearErrorStack();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
es = error_get_my_stack();
|
|
|
|
if( (error_stack *)NULL == es ) {
|
|
|
|
/* Oh, well. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (es->header.count < es->header.space) {
|
|
|
|
es->stack[ es->header.count++ ] = error;
|
|
|
|
} else {
|
|
|
|
memmove(es->stack, es->stack + 1,
|
|
|
|
(es->header.space - 1) * (sizeof es->stack[0]));
|
|
|
|
es->stack[ es->header.space - 1 ] = error;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nss_ClearErrorStack
|
|
|
|
*
|
|
|
|
* This routine clears the calling thread's error stack.
|
|
|
|
*/
|
|
|
|
|
|
|
|
NSS_IMPLEMENT void
|
|
|
|
nss_ClearErrorStack ( void)
|
|
|
|
{
|
|
|
|
error_stack *es = error_get_my_stack();
|
|
|
|
if( (error_stack *)NULL == es ) {
|
|
|
|
/* Oh, well. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
es->header.count = 0;
|
|
|
|
es->stack[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
2008-08-14 21:12:54 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* nss_DestroyErrorStack
|
|
|
|
*
|
|
|
|
* This routine frees the calling thread's error stack.
|
|
|
|
*/
|
|
|
|
|
|
|
|
NSS_IMPLEMENT void
|
|
|
|
nss_DestroyErrorStack ( void)
|
|
|
|
{
|
|
|
|
if( INVALID_TPD_INDEX != error_stack_index ) {
|
|
|
|
PR_SetThreadPrivate(error_stack_index, NULL);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|