security/nss/lib/base/error.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 /*
     6  * error.c
     7  *
     8  * This file contains the code implementing the per-thread error 
     9  * stacks upon which most NSS routines report their errors.
    10  */
    12 #ifndef BASE_H
    13 #include "base.h"
    14 #endif /* BASE_H */
    15 #include <limits.h> /* for UINT_MAX */
    16 #include <string.h> /* for memmove */
    18 #define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
    20 /*
    21  * The stack itself has a header, and a sequence of integers.
    22  * The header records the amount of space (as measured in stack
    23  * slots) already allocated for the stack, and the count of the
    24  * number of records currently being used.
    25  */
    27 struct stack_header_str {
    28   PRUint16 space;
    29   PRUint16 count;
    30 };
    32 struct error_stack_str {
    33   struct stack_header_str header;
    34   PRInt32 stack[1];
    35 };
    36 typedef struct error_stack_str error_stack;
    38 /*
    39  * error_stack_index
    40  *
    41  * Thread-private data must be indexed.  This is that index.
    42  * See PR_NewThreadPrivateIndex for more information.
    43  *
    44  * Thread-private data indexes are in the range [0, 127].
    45  */
    47 #define INVALID_TPD_INDEX UINT_MAX
    48 static PRUintn error_stack_index = INVALID_TPD_INDEX;
    50 /*
    51  * call_once
    52  *
    53  * The thread-private index must be obtained (once!) at runtime.
    54  * This block is used for that one-time call.
    55  */
    57 static PRCallOnceType error_call_once;
    59 /*
    60  * error_once_function
    61  *
    62  * This is the once-called callback.
    63  */
    64 static PRStatus
    65 error_once_function ( void)
    66 {
    67   return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
    68 }
    70 /*
    71  * error_get_my_stack
    72  *
    73  * This routine returns the calling thread's error stack, creating
    74  * it if necessary.  It may return NULL upon error, which implicitly
    75  * means that it ran out of memory.
    76  */
    78 static error_stack *
    79 error_get_my_stack ( void)
    80 {
    81   PRStatus st;
    82   error_stack *rv;
    83   PRUintn new_size;
    84   PRUint32 new_bytes;
    85   error_stack *new_stack;
    87   if( INVALID_TPD_INDEX == error_stack_index ) {
    88     st = PR_CallOnce(&error_call_once, error_once_function);
    89     if( PR_SUCCESS != st ) {
    90       return (error_stack *)NULL;
    91     }
    92   }
    94   rv = (error_stack *)PR_GetThreadPrivate(error_stack_index);
    95   if( (error_stack *)NULL == rv ) {
    96     /* Doesn't exist; create one */
    97     new_size = 16;
    98   } else if( rv->header.count == rv->header.space  &&
    99              rv->header.count  < NSS_MAX_ERROR_STACK_COUNT ) {
   100     /* Too small, expand it */
   101     new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
   102   } else {
   103     /* Okay, return it */
   104     return rv;
   105   }
   107   new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
   108   /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
   109   new_stack = PR_Calloc(1, new_bytes);
   111   if( (error_stack *)NULL != new_stack ) {
   112     if( (error_stack *)NULL != rv ) {
   113 	(void)nsslibc_memcpy(new_stack,rv,rv->header.space);
   114     }
   115     new_stack->header.space = new_size;
   116   }
   118   /* Set the value, whether or not the allocation worked */
   119   PR_SetThreadPrivate(error_stack_index, new_stack);
   120   return new_stack;
   121 }
   123 /*
   124  * The error stack
   125  *
   126  * The public methods relating to the error stack are:
   127  *
   128  *  NSS_GetError
   129  *  NSS_GetErrorStack
   130  *
   131  * The nonpublic methods relating to the error stack are:
   132  *
   133  *  nss_SetError
   134  *  nss_ClearErrorStack
   135  *
   136  */
   138 /*
   139  * NSS_GetError
   140  *
   141  * This routine returns the highest-level (most general) error set
   142  * by the most recent NSS library routine called by the same thread
   143  * calling this routine.
   144  *
   145  * This routine cannot fail.  However, it may return zero, which
   146  * indicates that the previous NSS library call did not set an error.
   147  *
   148  * Return value:
   149  *  0 if no error has been set
   150  *  A nonzero error number
   151  */
   153 NSS_IMPLEMENT PRInt32
   154 NSS_GetError ( void)
   155 {
   156   error_stack *es = error_get_my_stack();
   158   if( (error_stack *)NULL == es ) {
   159     return NSS_ERROR_NO_MEMORY; /* Good guess! */
   160   }
   162   if( 0 == es->header.count ) {
   163     return 0;
   164   }
   166   return es->stack[ es->header.count-1 ];
   167 }
   169 /*
   170  * NSS_GetErrorStack
   171  *
   172  * This routine returns a pointer to an array of integers, containing
   173  * the entire sequence or "stack" of errors set by the most recent NSS
   174  * library routine called by the same thread calling this routine.
   175  * NOTE: the caller DOES NOT OWN the memory pointed to by the return
   176  * value.  The pointer will remain valid until the calling thread
   177  * calls another NSS routine.  The lowest-level (most specific) error 
   178  * is first in the array, and the highest-level is last.  The array is
   179  * zero-terminated.  This routine may return NULL upon error; this
   180  * indicates a low-memory situation.
   181  *
   182  * Return value:
   183  *  NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
   184  *  A NON-caller-owned pointer to an array of integers
   185  */
   187 NSS_IMPLEMENT PRInt32 *
   188 NSS_GetErrorStack ( void)
   189 {
   190   error_stack *es = error_get_my_stack();
   192   if( (error_stack *)NULL == es ) {
   193     return (PRInt32 *)NULL;
   194   }
   196   /* Make sure it's terminated */
   197   es->stack[ es->header.count ] = 0;
   199   return es->stack;
   200 }
   202 /*
   203  * nss_SetError
   204  *
   205  * This routine places a new error code on the top of the calling 
   206  * thread's error stack.  Calling this routine wiht an error code
   207  * of zero will clear the error stack.
   208  */
   210 NSS_IMPLEMENT void
   211 nss_SetError ( PRUint32 error)
   212 {
   213   error_stack *es;
   215   if( 0 == error ) {
   216     nss_ClearErrorStack();
   217     return;
   218   }
   220   es = error_get_my_stack();
   221   if( (error_stack *)NULL == es ) {
   222     /* Oh, well. */
   223     return;
   224   }
   226   if (es->header.count < es->header.space) {
   227     es->stack[ es->header.count++ ] = error;
   228   } else {
   229     memmove(es->stack, es->stack + 1, 
   230 		(es->header.space - 1) * (sizeof es->stack[0]));
   231     es->stack[ es->header.space - 1 ] = error;
   232   }
   233   return;
   234 }
   236 /*
   237  * nss_ClearErrorStack
   238  *
   239  * This routine clears the calling thread's error stack.
   240  */
   242 NSS_IMPLEMENT void
   243 nss_ClearErrorStack ( void)
   244 {
   245   error_stack *es = error_get_my_stack();
   246   if( (error_stack *)NULL == es ) {
   247     /* Oh, well. */
   248     return;
   249   }
   251   es->header.count = 0;
   252   es->stack[0] = 0;
   253   return;
   254 }
   256 /*
   257  * nss_DestroyErrorStack
   258  *
   259  * This routine frees the calling thread's error stack.
   260  */
   262 NSS_IMPLEMENT void
   263 nss_DestroyErrorStack ( void)
   264 {
   265   if( INVALID_TPD_INDEX != error_stack_index ) {
   266     PR_SetThreadPrivate(error_stack_index, NULL);
   267   }
   268   return;
   269 }

mercurial