security/nss/lib/util/secport.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/secport.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,718 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * secport.c - portability interfaces for security libraries
    1.10 + *
    1.11 + * This file abstracts out libc functionality that libsec depends on
    1.12 + * 
    1.13 + * NOTE - These are not public interfaces
    1.14 + */
    1.15 +
    1.16 +#include "seccomon.h"
    1.17 +#include "prmem.h"
    1.18 +#include "prerror.h"
    1.19 +#include "plarena.h"
    1.20 +#include "secerr.h"
    1.21 +#include "prmon.h"
    1.22 +#include "nssilock.h"
    1.23 +#include "secport.h"
    1.24 +#include "prenv.h"
    1.25 +
    1.26 +#ifdef DEBUG
    1.27 +#define THREADMARK
    1.28 +#endif /* DEBUG */
    1.29 +
    1.30 +#ifdef THREADMARK
    1.31 +#include "prthread.h"
    1.32 +#endif /* THREADMARK */
    1.33 +
    1.34 +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
    1.35 +#include <stdlib.h>
    1.36 +#else
    1.37 +#include "wtypes.h"
    1.38 +#endif
    1.39 +
    1.40 +#define SET_ERROR_CODE	/* place holder for code to set PR error code. */
    1.41 +
    1.42 +#ifdef THREADMARK
    1.43 +typedef struct threadmark_mark_str {
    1.44 +  struct threadmark_mark_str *next;
    1.45 +  void *mark;
    1.46 +} threadmark_mark;
    1.47 +
    1.48 +#endif /* THREADMARK */
    1.49 +
    1.50 +/* The value of this magic must change each time PORTArenaPool changes. */
    1.51 +#define ARENAPOOL_MAGIC 0xB8AC9BDF 
    1.52 +
    1.53 +typedef struct PORTArenaPool_str {
    1.54 +  PLArenaPool arena;
    1.55 +  PRUint32    magic;
    1.56 +  PRLock *    lock;
    1.57 +#ifdef THREADMARK
    1.58 +  PRThread *marking_thread;
    1.59 +  threadmark_mark *first_mark;
    1.60 +#endif
    1.61 +} PORTArenaPool;
    1.62 +
    1.63 +
    1.64 +/* count of allocation failures. */
    1.65 +unsigned long port_allocFailures;
    1.66 +
    1.67 +/* locations for registering Unicode conversion functions.  
    1.68 + * XXX is this the appropriate location?  or should they be
    1.69 + *     moved to client/server specific locations?
    1.70 + */
    1.71 +PORTCharConversionFunc ucs4Utf8ConvertFunc;
    1.72 +PORTCharConversionFunc ucs2Utf8ConvertFunc;
    1.73 +PORTCharConversionWSwapFunc  ucs2AsciiConvertFunc;
    1.74 +
    1.75 +/* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc)
    1.76 + * use the PRUint32 type for the size parameter. Before we pass a size_t or
    1.77 + * unsigned long size to these functions, we need to ensure it is <= half of
    1.78 + * the maximum PRUint32 value to avoid truncation and catch a negative size.
    1.79 + */
    1.80 +#define MAX_SIZE (PR_UINT32_MAX >> 1)
    1.81 +
    1.82 +void *
    1.83 +PORT_Alloc(size_t bytes)
    1.84 +{
    1.85 +    void *rv = NULL;
    1.86 +
    1.87 +    if (bytes <= MAX_SIZE) {
    1.88 +	/* Always allocate a non-zero amount of bytes */
    1.89 +	rv = PR_Malloc(bytes ? bytes : 1);
    1.90 +    }
    1.91 +    if (!rv) {
    1.92 +	++port_allocFailures;
    1.93 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
    1.94 +    }
    1.95 +    return rv;
    1.96 +}
    1.97 +
    1.98 +void *
    1.99 +PORT_Realloc(void *oldptr, size_t bytes)
   1.100 +{
   1.101 +    void *rv = NULL;
   1.102 +
   1.103 +    if (bytes <= MAX_SIZE) {
   1.104 +	rv = PR_Realloc(oldptr, bytes);
   1.105 +    }
   1.106 +    if (!rv) {
   1.107 +	++port_allocFailures;
   1.108 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.109 +    }
   1.110 +    return rv;
   1.111 +}
   1.112 +
   1.113 +void *
   1.114 +PORT_ZAlloc(size_t bytes)
   1.115 +{
   1.116 +    void *rv = NULL;
   1.117 +
   1.118 +    if (bytes <= MAX_SIZE) {
   1.119 +	/* Always allocate a non-zero amount of bytes */
   1.120 +	rv = PR_Calloc(1, bytes ? bytes : 1);
   1.121 +    }
   1.122 +    if (!rv) {
   1.123 +	++port_allocFailures;
   1.124 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.125 +    }
   1.126 +    return rv;
   1.127 +}
   1.128 +
   1.129 +void
   1.130 +PORT_Free(void *ptr)
   1.131 +{
   1.132 +    if (ptr) {
   1.133 +	PR_Free(ptr);
   1.134 +    }
   1.135 +}
   1.136 +
   1.137 +void
   1.138 +PORT_ZFree(void *ptr, size_t len)
   1.139 +{
   1.140 +    if (ptr) {
   1.141 +	memset(ptr, 0, len);
   1.142 +	PR_Free(ptr);
   1.143 +    }
   1.144 +}
   1.145 +
   1.146 +char *
   1.147 +PORT_Strdup(const char *str)
   1.148 +{
   1.149 +    size_t len = PORT_Strlen(str)+1;
   1.150 +    char *newstr;
   1.151 +
   1.152 +    newstr = (char *)PORT_Alloc(len);
   1.153 +    if (newstr) {
   1.154 +        PORT_Memcpy(newstr, str, len);
   1.155 +    }
   1.156 +    return newstr;
   1.157 +}
   1.158 +
   1.159 +void
   1.160 +PORT_SetError(int value)
   1.161 +{	
   1.162 +#ifdef DEBUG_jp96085
   1.163 +    PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
   1.164 +#endif
   1.165 +    PR_SetError(value, 0);
   1.166 +    return;
   1.167 +}
   1.168 +
   1.169 +int
   1.170 +PORT_GetError(void)
   1.171 +{
   1.172 +    return(PR_GetError());
   1.173 +}
   1.174 +
   1.175 +/********************* Arena code follows *****************************
   1.176 + * ArenaPools are like heaps.  The memory in them consists of large blocks,
   1.177 + * called arenas, which are allocated from the/a system heap.  Inside an
   1.178 + * ArenaPool, the arenas are organized as if they were in a stack.  Newly
   1.179 + * allocated arenas are "pushed" on that stack.  When you attempt to
   1.180 + * allocate memory from an ArenaPool, the code first looks to see if there
   1.181 + * is enough unused space in the top arena on the stack to satisfy your
   1.182 + * request, and if so, your request is satisfied from that arena.
   1.183 + * Otherwise, a new arena is allocated (or taken from NSPR's list of freed
   1.184 + * arenas) and pushed on to the stack.  The new arena is always big enough
   1.185 + * to satisfy the request, and is also at least a minimum size that is
   1.186 + * established at the time that the ArenaPool is created.
   1.187 + *
   1.188 + * The ArenaMark function returns the address of a marker in the arena at
   1.189 + * the top of the arena stack.  It is the address of the place in the arena
   1.190 + * on the top of the arena stack from which the next block of memory will
   1.191 + * be allocated.  Each ArenaPool has its own separate stack, and hence
   1.192 + * marks are only relevant to the ArenaPool from which they are gotten.
   1.193 + * Marks may be nested.  That is, a thread can get a mark, and then get
   1.194 + * another mark.
   1.195 + *
   1.196 + * It is intended that all the marks in an ArenaPool may only be owned by a
   1.197 + * single thread.  In DEBUG builds, this is enforced.  In non-DEBUG builds,
   1.198 + * it is not.  In DEBUG builds, when a thread gets a mark from an
   1.199 + * ArenaPool, no other thread may acquire a mark in that ArenaPool while
   1.200 + * that mark exists, that is, until that mark is unmarked or released.
   1.201 + * Therefore, it is important that every mark be unmarked or released when
   1.202 + * the creating thread has no further need for exclusive ownership of the
   1.203 + * right to manage the ArenaPool.
   1.204 + *
   1.205 + * The ArenaUnmark function discards the ArenaMark at the address given,
   1.206 + * and all marks nested inside that mark (that is, acquired from that same
   1.207 + * ArenaPool while that mark existed).   It is an error for a thread other
   1.208 + * than the mark's creator to try to unmark it.  When a thread has unmarked
   1.209 + * all its marks from an ArenaPool, then another thread is able to set
   1.210 + * marks in that ArenaPool.  ArenaUnmark does not deallocate (or "pop") any
   1.211 + * memory allocated from the ArenaPool since the mark was created.
   1.212 + *
   1.213 + * ArenaRelease "pops" the stack back to the mark, deallocating all the
   1.214 + * memory allocated from the arenas in the ArenaPool since that mark was
   1.215 + * created, and removing any arenas from the ArenaPool that have no
   1.216 + * remaining active allocations when that is done.  It implicitly releases
   1.217 + * any marks nested inside the mark being explicitly released.  It is the
   1.218 + * only operation, other than destroying the arenapool, that potentially
   1.219 + * reduces the number of arenas on the stack.  Otherwise, the stack grows
   1.220 + * until the arenapool is destroyed, at which point all the arenas are
   1.221 + * freed or returned to a "free arena list", depending on their sizes.
   1.222 + */
   1.223 +PLArenaPool *
   1.224 +PORT_NewArena(unsigned long chunksize)
   1.225 +{
   1.226 +    PORTArenaPool *pool;
   1.227 +    
   1.228 +    if (chunksize > MAX_SIZE) {
   1.229 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.230 +	return NULL;
   1.231 +    }
   1.232 +    pool = PORT_ZNew(PORTArenaPool);
   1.233 +    if (!pool) {
   1.234 +	return NULL;
   1.235 +    }
   1.236 +    pool->magic = ARENAPOOL_MAGIC;
   1.237 +    pool->lock = PZ_NewLock(nssILockArena);
   1.238 +    if (!pool->lock) {
   1.239 +	++port_allocFailures;
   1.240 +	PORT_Free(pool);
   1.241 +	return NULL;
   1.242 +    }
   1.243 +    PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
   1.244 +    return(&pool->arena);
   1.245 +}
   1.246 +
   1.247 +void *
   1.248 +PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
   1.249 +{
   1.250 +    void *p = NULL;
   1.251 +
   1.252 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.253 +
   1.254 +    if (size <= 0) {
   1.255 +	size = 1;
   1.256 +    }
   1.257 +
   1.258 +    if (size > MAX_SIZE) {
   1.259 +	/* you lose. */
   1.260 +    } else 
   1.261 +    /* Is it one of ours?  Assume so and check the magic */
   1.262 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.263 +	PZ_Lock(pool->lock);
   1.264 +#ifdef THREADMARK
   1.265 +        /* Most likely one of ours.  Is there a thread id? */
   1.266 +	if (pool->marking_thread  &&
   1.267 +	    pool->marking_thread != PR_GetCurrentThread() ) {
   1.268 +	    /* Another thread holds a mark in this arena */
   1.269 +	    PZ_Unlock(pool->lock);
   1.270 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.271 +	    PORT_Assert(0);
   1.272 +	    return NULL;
   1.273 +	} /* tid != null */
   1.274 +#endif /* THREADMARK */
   1.275 +	PL_ARENA_ALLOCATE(p, arena, size);
   1.276 +	PZ_Unlock(pool->lock);
   1.277 +    } else {
   1.278 +	PL_ARENA_ALLOCATE(p, arena, size);
   1.279 +    }
   1.280 +
   1.281 +    if (!p) {
   1.282 +	++port_allocFailures;
   1.283 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.284 +    }
   1.285 +
   1.286 +    return(p);
   1.287 +}
   1.288 +
   1.289 +void *
   1.290 +PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
   1.291 +{
   1.292 +    void *p;
   1.293 +
   1.294 +    if (size <= 0)
   1.295 +        size = 1;
   1.296 +
   1.297 +    p = PORT_ArenaAlloc(arena, size);
   1.298 +
   1.299 +    if (p) {
   1.300 +	PORT_Memset(p, 0, size);
   1.301 +    }
   1.302 +
   1.303 +    return(p);
   1.304 +}
   1.305 +
   1.306 +/*
   1.307 + * If zero is true, zeroize the arena memory before freeing it.
   1.308 + */
   1.309 +void
   1.310 +PORT_FreeArena(PLArenaPool *arena, PRBool zero)
   1.311 +{
   1.312 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.313 +    PRLock *       lock = (PRLock *)0;
   1.314 +    size_t         len  = sizeof *arena;
   1.315 +    static PRBool  checkedEnv = PR_FALSE;
   1.316 +    static PRBool  doFreeArenaPool = PR_FALSE;
   1.317 +
   1.318 +    if (!pool)
   1.319 +    	return;
   1.320 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.321 +	len  = sizeof *pool;
   1.322 +	lock = pool->lock;
   1.323 +	PZ_Lock(lock);
   1.324 +    }
   1.325 +    if (!checkedEnv) {
   1.326 +	/* no need for thread protection here */
   1.327 +	doFreeArenaPool = (PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
   1.328 +	checkedEnv = PR_TRUE;
   1.329 +    }
   1.330 +    if (zero) {
   1.331 +	PL_ClearArenaPool(arena, 0);
   1.332 +    }
   1.333 +    if (doFreeArenaPool) {
   1.334 +	PL_FreeArenaPool(arena);
   1.335 +    } else {
   1.336 +	PL_FinishArenaPool(arena);
   1.337 +    }
   1.338 +    PORT_ZFree(arena, len);
   1.339 +    if (lock) {
   1.340 +	PZ_Unlock(lock);
   1.341 +	PZ_DestroyLock(lock);
   1.342 +    }
   1.343 +}
   1.344 +
   1.345 +void *
   1.346 +PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
   1.347 +{
   1.348 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.349 +    PORT_Assert(newsize >= oldsize);
   1.350 +    
   1.351 +    if (newsize > MAX_SIZE) {
   1.352 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.353 +	return NULL;
   1.354 +    }
   1.355 +
   1.356 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.357 +	PZ_Lock(pool->lock);
   1.358 +	/* Do we do a THREADMARK check here? */
   1.359 +	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
   1.360 +	PZ_Unlock(pool->lock);
   1.361 +    } else {
   1.362 +	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
   1.363 +    }
   1.364 +    
   1.365 +    return(ptr);
   1.366 +}
   1.367 +
   1.368 +void *
   1.369 +PORT_ArenaMark(PLArenaPool *arena)
   1.370 +{
   1.371 +    void * result;
   1.372 +
   1.373 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.374 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.375 +	PZ_Lock(pool->lock);
   1.376 +#ifdef THREADMARK
   1.377 +	{
   1.378 +	  threadmark_mark *tm, **pw;
   1.379 +	  PRThread * currentThread = PR_GetCurrentThread();
   1.380 +
   1.381 +	    if (! pool->marking_thread ) {
   1.382 +		/* First mark */
   1.383 +		pool->marking_thread = currentThread;
   1.384 +	    } else if (currentThread != pool->marking_thread ) {
   1.385 +		PZ_Unlock(pool->lock);
   1.386 +		PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.387 +		PORT_Assert(0);
   1.388 +		return NULL;
   1.389 +	    }
   1.390 +
   1.391 +	    result = PL_ARENA_MARK(arena);
   1.392 +	    PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
   1.393 +	    if (!tm) {
   1.394 +		PZ_Unlock(pool->lock);
   1.395 +		PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.396 +		return NULL;
   1.397 +	    }
   1.398 +
   1.399 +	    tm->mark = result;
   1.400 +	    tm->next = (threadmark_mark *)NULL;
   1.401 +
   1.402 +	    pw = &pool->first_mark;
   1.403 +	    while( *pw ) {
   1.404 +		 pw = &(*pw)->next;
   1.405 +	    }
   1.406 +
   1.407 +	    *pw = tm;
   1.408 +	}
   1.409 +#else /* THREADMARK */
   1.410 +	result = PL_ARENA_MARK(arena);
   1.411 +#endif /* THREADMARK */
   1.412 +	PZ_Unlock(pool->lock);
   1.413 +    } else {
   1.414 +	/* a "pure" NSPR arena */
   1.415 +	result = PL_ARENA_MARK(arena);
   1.416 +    }
   1.417 +    return result;
   1.418 +}
   1.419 +
   1.420 +/*
   1.421 + * This function accesses the internals of PLArena, which is why it needs
   1.422 + * to use the NSPR internal macro PL_MAKE_MEM_UNDEFINED before the memset
   1.423 + * calls.
   1.424 + *
   1.425 + * We should move this function to NSPR as PL_ClearArenaAfterMark or add
   1.426 + * a PL_ARENA_CLEAR_AND_RELEASE macro.
   1.427 + *
   1.428 + * TODO: remove the #ifdef PL_MAKE_MEM_UNDEFINED tests when NSPR 4.10+ is
   1.429 + * widely available.
   1.430 + */
   1.431 +static void
   1.432 +port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
   1.433 +{
   1.434 +    PLArena *a = arena->current;
   1.435 +    if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
   1.436 +	/* fast path: mark falls in the current arena */
   1.437 +#ifdef PL_MAKE_MEM_UNDEFINED
   1.438 +	PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
   1.439 +#endif
   1.440 +	memset(mark, 0, a->avail - (PRUword)mark);
   1.441 +    } else {
   1.442 +	/* slow path: need to find the arena that mark falls in */
   1.443 +	for (a = arena->first.next; a; a = a->next) {
   1.444 +	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
   1.445 +	    if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
   1.446 +#ifdef PL_MAKE_MEM_UNDEFINED
   1.447 +		PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
   1.448 +#endif
   1.449 +		memset(mark, 0, a->avail - (PRUword)mark);
   1.450 +		a = a->next;
   1.451 +		break;
   1.452 +	    }
   1.453 +	}
   1.454 +	for (; a; a = a->next) {
   1.455 +	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
   1.456 +#ifdef PL_MAKE_MEM_UNDEFINED
   1.457 +	    PL_MAKE_MEM_UNDEFINED((void *)a->base, a->avail - a->base);
   1.458 +#endif
   1.459 +	    memset((void *)a->base, 0, a->avail - a->base);
   1.460 +	}
   1.461 +    }
   1.462 +}
   1.463 +
   1.464 +static void
   1.465 +port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
   1.466 +{
   1.467 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.468 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.469 +	PZ_Lock(pool->lock);
   1.470 +#ifdef THREADMARK
   1.471 +	{
   1.472 +	    threadmark_mark **pw, *tm;
   1.473 +
   1.474 +	    if (PR_GetCurrentThread() != pool->marking_thread ) {
   1.475 +		PZ_Unlock(pool->lock);
   1.476 +		PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.477 +		PORT_Assert(0);
   1.478 +		return /* no error indication available */ ;
   1.479 +	    }
   1.480 +
   1.481 +	    pw = &pool->first_mark;
   1.482 +	    while( *pw && (mark != (*pw)->mark) ) {
   1.483 +		pw = &(*pw)->next;
   1.484 +	    }
   1.485 +
   1.486 +	    if (! *pw ) {
   1.487 +		/* bad mark */
   1.488 +		PZ_Unlock(pool->lock);
   1.489 +		PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.490 +		PORT_Assert(0);
   1.491 +		return /* no error indication available */ ;
   1.492 +	    }
   1.493 +
   1.494 +	    tm = *pw;
   1.495 +	    *pw = (threadmark_mark *)NULL;
   1.496 +
   1.497 +	    if (zero) {
   1.498 +		port_ArenaZeroAfterMark(arena, mark);
   1.499 +	    }
   1.500 +	    PL_ARENA_RELEASE(arena, mark);
   1.501 +
   1.502 +	    if (! pool->first_mark ) {
   1.503 +		pool->marking_thread = (PRThread *)NULL;
   1.504 +	    }
   1.505 +	}
   1.506 +#else /* THREADMARK */
   1.507 +	if (zero) {
   1.508 +	    port_ArenaZeroAfterMark(arena, mark);
   1.509 +	}
   1.510 +	PL_ARENA_RELEASE(arena, mark);
   1.511 +#endif /* THREADMARK */
   1.512 +	PZ_Unlock(pool->lock);
   1.513 +    } else {
   1.514 +	if (zero) {
   1.515 +	    port_ArenaZeroAfterMark(arena, mark);
   1.516 +	}
   1.517 +	PL_ARENA_RELEASE(arena, mark);
   1.518 +    }
   1.519 +}
   1.520 +
   1.521 +void
   1.522 +PORT_ArenaRelease(PLArenaPool *arena, void *mark)
   1.523 +{
   1.524 +    port_ArenaRelease(arena, mark, PR_FALSE);
   1.525 +}
   1.526 +
   1.527 +/*
   1.528 + * Zeroize the arena memory before releasing it.
   1.529 + */
   1.530 +void
   1.531 +PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
   1.532 +{
   1.533 +    port_ArenaRelease(arena, mark, PR_TRUE);
   1.534 +}
   1.535 +
   1.536 +void
   1.537 +PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
   1.538 +{
   1.539 +#ifdef THREADMARK
   1.540 +    PORTArenaPool *pool = (PORTArenaPool *)arena;
   1.541 +    if (ARENAPOOL_MAGIC == pool->magic ) {
   1.542 +	threadmark_mark **pw, *tm;
   1.543 +
   1.544 +	PZ_Lock(pool->lock);
   1.545 +
   1.546 +	if (PR_GetCurrentThread() != pool->marking_thread ) {
   1.547 +	    PZ_Unlock(pool->lock);
   1.548 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.549 +	    PORT_Assert(0);
   1.550 +	    return /* no error indication available */ ;
   1.551 +	}
   1.552 +
   1.553 +	pw = &pool->first_mark;
   1.554 +	while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
   1.555 +	    pw = &(*pw)->next;
   1.556 +	}
   1.557 +
   1.558 +	if ((threadmark_mark *)NULL == *pw ) {
   1.559 +	    /* bad mark */
   1.560 +	    PZ_Unlock(pool->lock);
   1.561 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.562 +	    PORT_Assert(0);
   1.563 +	    return /* no error indication available */ ;
   1.564 +	}
   1.565 +
   1.566 +	tm = *pw;
   1.567 +	*pw = (threadmark_mark *)NULL;
   1.568 +
   1.569 +	if (! pool->first_mark ) {
   1.570 +	    pool->marking_thread = (PRThread *)NULL;
   1.571 +	}
   1.572 +
   1.573 +	PZ_Unlock(pool->lock);
   1.574 +    }
   1.575 +#endif /* THREADMARK */
   1.576 +}
   1.577 +
   1.578 +char *
   1.579 +PORT_ArenaStrdup(PLArenaPool *arena, const char *str) {
   1.580 +    int len = PORT_Strlen(str)+1;
   1.581 +    char *newstr;
   1.582 +
   1.583 +    newstr = (char*)PORT_ArenaAlloc(arena,len);
   1.584 +    if (newstr) {
   1.585 +        PORT_Memcpy(newstr,str,len);
   1.586 +    }
   1.587 +    return newstr;
   1.588 +}
   1.589 +
   1.590 +/********************** end of arena functions ***********************/
   1.591 +
   1.592 +/****************** unicode conversion functions ***********************/
   1.593 +/*
   1.594 + * NOTE: These conversion functions all assume that the multibyte
   1.595 + * characters are going to be in NETWORK BYTE ORDER, not host byte
   1.596 + * order.  This is because the only time we deal with UCS-2 and UCS-4
   1.597 + * are when the data was received from or is going to be sent out
   1.598 + * over the wire (in, e.g. certificates).
   1.599 + */
   1.600 +
   1.601 +void
   1.602 +PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
   1.603 +{ 
   1.604 +    ucs4Utf8ConvertFunc = convFunc;
   1.605 +}
   1.606 +
   1.607 +void
   1.608 +PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
   1.609 +{ 
   1.610 +    ucs2AsciiConvertFunc = convFunc;
   1.611 +}
   1.612 +
   1.613 +void
   1.614 +PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
   1.615 +{ 
   1.616 +    ucs2Utf8ConvertFunc = convFunc;
   1.617 +}
   1.618 +
   1.619 +PRBool 
   1.620 +PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
   1.621 +			 unsigned int inBufLen, unsigned char *outBuf,
   1.622 +			 unsigned int maxOutBufLen, unsigned int *outBufLen)
   1.623 +{
   1.624 +    if(!ucs4Utf8ConvertFunc) {
   1.625 +      return sec_port_ucs4_utf8_conversion_function(toUnicode,
   1.626 +        inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
   1.627 +    }
   1.628 +
   1.629 +    return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
   1.630 +				  maxOutBufLen, outBufLen);
   1.631 +}
   1.632 +
   1.633 +PRBool 
   1.634 +PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
   1.635 +			 unsigned int inBufLen, unsigned char *outBuf,
   1.636 +			 unsigned int maxOutBufLen, unsigned int *outBufLen)
   1.637 +{
   1.638 +    if(!ucs2Utf8ConvertFunc) {
   1.639 +      return sec_port_ucs2_utf8_conversion_function(toUnicode,
   1.640 +        inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
   1.641 +    }
   1.642 +
   1.643 +    return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
   1.644 +				  maxOutBufLen, outBufLen);
   1.645 +}
   1.646 +
   1.647 +PRBool 
   1.648 +PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
   1.649 +			 unsigned int inBufLen, unsigned char *outBuf,
   1.650 +			 unsigned int maxOutBufLen, unsigned int *outBufLen)
   1.651 +{
   1.652 +    return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
   1.653 +      outBuf, maxOutBufLen, outBufLen);
   1.654 +}
   1.655 +
   1.656 +PRBool 
   1.657 +PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
   1.658 +			  unsigned int inBufLen, unsigned char *outBuf,
   1.659 +			  unsigned int maxOutBufLen, unsigned int *outBufLen,
   1.660 +			  PRBool swapBytes)
   1.661 +{
   1.662 +    if(!ucs2AsciiConvertFunc) {
   1.663 +	return PR_FALSE;
   1.664 +    }
   1.665 +
   1.666 +    return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf, 
   1.667 +				  maxOutBufLen, outBufLen, swapBytes);
   1.668 +}
   1.669 +
   1.670 +
   1.671 +/* Portable putenv.  Creates/replaces an environment variable of the form
   1.672 + *  envVarName=envValue
   1.673 + */
   1.674 +int
   1.675 +NSS_PutEnv(const char * envVarName, const char * envValue)
   1.676 +{
   1.677 +    SECStatus result = SECSuccess;
   1.678 +    char *    encoded;
   1.679 +    int       putEnvFailed;
   1.680 +#ifdef _WIN32
   1.681 +    PRBool      setOK;
   1.682 +
   1.683 +    setOK = SetEnvironmentVariable(envVarName, envValue);
   1.684 +    if (!setOK) {
   1.685 +        SET_ERROR_CODE
   1.686 +        return SECFailure;
   1.687 +    }
   1.688 +#endif
   1.689 +
   1.690 +    encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
   1.691 +    strcpy(encoded, envVarName);
   1.692 +    strcat(encoded, "=");
   1.693 +    strcat(encoded, envValue);
   1.694 +
   1.695 +    putEnvFailed = putenv(encoded); /* adopt. */
   1.696 +    if (putEnvFailed) {
   1.697 +        SET_ERROR_CODE
   1.698 +        result = SECFailure;
   1.699 +        PORT_Free(encoded);
   1.700 +    }
   1.701 +    return result;
   1.702 +}
   1.703 +
   1.704 +/*
   1.705 + * Perform a constant-time compare of two memory regions. The return value is
   1.706 + * 0 if the memory regions are equal and non-zero otherwise.
   1.707 + */
   1.708 +int
   1.709 +NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
   1.710 +{
   1.711 +    const unsigned char *a = (const unsigned char*) ia;
   1.712 +    const unsigned char *b = (const unsigned char*) ib;
   1.713 +    size_t i;
   1.714 +    unsigned char r = 0;
   1.715 +
   1.716 +    for (i = 0; i < n; ++i) {
   1.717 +        r |= *a++ ^ *b++;
   1.718 +    }
   1.719 +
   1.720 +    return r;
   1.721 +}

mercurial