DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
 * error.c
 *
 * This file contains the code implementing the per-thread error
 * stacks upon which most NSS routines report their errors.
 * stacks upon which most NSS routines report their errors.
 */

#ifndef BASE_H
#include "base.h"
#endif              /* BASE_H */
#endif              /* BASE_H */
#include <limits.h> /* for UINT_MAX */
#include <string.h> /* for memmove */

#if defined(__MINGW32__)
#include <windows.h>
#include <windows.h>
#endif

#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
 * 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 {
struct stack_header_str {
    PRUint16 space;
    PRUint16 count;
};

struct error_stack_str {
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.
 * See PR_NewThreadPrivateIndex for more information.
 *
 * Thread-private data indexes are in the range [0, 127].
 */


#define INVALID_TPD_INDEX UINT_MAX
static PRUintn error_stack_index = INVALID_TPD_INDEX;


/*
 * call_once
 *
 * The thread-private index must be obtained (once!) at runtime.
 * This block is used for that one-time call.
 * This block is used for that one-time call.
 */

static PRCallOnceType error_call_once;
static const PRCallOnceType error_call_again;


/*
 * error_once_function
 *
 * This is the once-called callback.
 */
 */
static PRStatus
error_once_function(void)
{

/*
 * This #ifdef function is redundant. It performs the same thing as the
 * else case.
 * else case.
 *
 * However, the MinGW version looks up the function from nss3's export
 * table, and on MinGW _that_ behaves differently than passing a
 * function pointer in a different module because MinGW has
 * -mnop-fun-dllimport specified, which generates function thunks for
 * cross-module calls. And when a module (like nssckbi) gets unloaded,
 * cross-module calls. And when a module (like nssckbi) gets unloaded,
 * and you try to call into that thunk (which is now missing) you'll
 * crash. So we do this bit of ugly to avoid that crash. Fortunately
 * this is the only place we've had to do this.
 */
#if defined(__MINGW32__)
    HMODULE nss3 = GetModuleHandleW(L"nss3");
    HMODULE nss3 = GetModuleHandleW(L"nss3");
    if (nss3) {
        FARPROC freePtr = GetProcAddress(nss3, "PR_Free");
        if (freePtr) {
            return PR_NewThreadPrivateIndex(&error_stack_index, freePtr);
        }
        }
    }
    return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
#else
    return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
#endif
#endif
}

/*
 * error_get_my_stack
 *
 *
 * This routine returns the calling thread's error stack, creating
 * 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 *
static error_stack *
error_get_my_stack(void)
{
    PRStatus st;
    error_stack *rv;
    PRUintn new_size;
    PRUintn new_size;
    PRUint32 new_bytes;
    error_stack *new_stack;

    if (INVALID_TPD_INDEX == error_stack_index) {
        st = PR_CallOnce(&error_call_once, error_once_function);
        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 &&
    } 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);
        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 != 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:
 * 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
 * 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
 *  0 if no error has been set
 *  A nonzero error number
 */

NSS_IMPLEMENT PRInt32
NSS_GetError(void)
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) {
    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
 * 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
 * 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:
 * 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_IMPLEMENT PRInt32 *
NSS_GetErrorStack(void)
{
    error_stack *es = error_get_my_stack();

    if ((error_stack *)NULL == es) {
    if ((error_stack *)NULL == es) {
        return (PRInt32 *)NULL;
    }

    /* Make sure it's terminated */
    es->stack[es->header.count] = 0;
    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.
 * of zero will clear the error stack.
 */

NSS_IMPLEMENT void
nss_SetError(PRUint32 error)
{
    error_stack *es;

    if (0 == error) {
    if (0 == error) {
        nss_ClearErrorStack();
        return;
    }

    es = error_get_my_stack();
    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,
        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.
 * 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;
}
}

/*
 * nss_DestroyErrorStack
 *
 * This routine frees the calling thread's error stack.
 * 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);
        error_stack_index = INVALID_TPD_INDEX;
        error_call_once = error_call_again; /* allow to init again */
    }
    return;
    return;
}