security/nss/lib/util/secport.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * secport.c - portability interfaces for security libraries
michael@0 7 *
michael@0 8 * This file abstracts out libc functionality that libsec depends on
michael@0 9 *
michael@0 10 * NOTE - These are not public interfaces
michael@0 11 */
michael@0 12
michael@0 13 #include "seccomon.h"
michael@0 14 #include "prmem.h"
michael@0 15 #include "prerror.h"
michael@0 16 #include "plarena.h"
michael@0 17 #include "secerr.h"
michael@0 18 #include "prmon.h"
michael@0 19 #include "nssilock.h"
michael@0 20 #include "secport.h"
michael@0 21 #include "prenv.h"
michael@0 22
michael@0 23 #ifdef DEBUG
michael@0 24 #define THREADMARK
michael@0 25 #endif /* DEBUG */
michael@0 26
michael@0 27 #ifdef THREADMARK
michael@0 28 #include "prthread.h"
michael@0 29 #endif /* THREADMARK */
michael@0 30
michael@0 31 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
michael@0 32 #include <stdlib.h>
michael@0 33 #else
michael@0 34 #include "wtypes.h"
michael@0 35 #endif
michael@0 36
michael@0 37 #define SET_ERROR_CODE /* place holder for code to set PR error code. */
michael@0 38
michael@0 39 #ifdef THREADMARK
michael@0 40 typedef struct threadmark_mark_str {
michael@0 41 struct threadmark_mark_str *next;
michael@0 42 void *mark;
michael@0 43 } threadmark_mark;
michael@0 44
michael@0 45 #endif /* THREADMARK */
michael@0 46
michael@0 47 /* The value of this magic must change each time PORTArenaPool changes. */
michael@0 48 #define ARENAPOOL_MAGIC 0xB8AC9BDF
michael@0 49
michael@0 50 typedef struct PORTArenaPool_str {
michael@0 51 PLArenaPool arena;
michael@0 52 PRUint32 magic;
michael@0 53 PRLock * lock;
michael@0 54 #ifdef THREADMARK
michael@0 55 PRThread *marking_thread;
michael@0 56 threadmark_mark *first_mark;
michael@0 57 #endif
michael@0 58 } PORTArenaPool;
michael@0 59
michael@0 60
michael@0 61 /* count of allocation failures. */
michael@0 62 unsigned long port_allocFailures;
michael@0 63
michael@0 64 /* locations for registering Unicode conversion functions.
michael@0 65 * XXX is this the appropriate location? or should they be
michael@0 66 * moved to client/server specific locations?
michael@0 67 */
michael@0 68 PORTCharConversionFunc ucs4Utf8ConvertFunc;
michael@0 69 PORTCharConversionFunc ucs2Utf8ConvertFunc;
michael@0 70 PORTCharConversionWSwapFunc ucs2AsciiConvertFunc;
michael@0 71
michael@0 72 /* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc)
michael@0 73 * use the PRUint32 type for the size parameter. Before we pass a size_t or
michael@0 74 * unsigned long size to these functions, we need to ensure it is <= half of
michael@0 75 * the maximum PRUint32 value to avoid truncation and catch a negative size.
michael@0 76 */
michael@0 77 #define MAX_SIZE (PR_UINT32_MAX >> 1)
michael@0 78
michael@0 79 void *
michael@0 80 PORT_Alloc(size_t bytes)
michael@0 81 {
michael@0 82 void *rv = NULL;
michael@0 83
michael@0 84 if (bytes <= MAX_SIZE) {
michael@0 85 /* Always allocate a non-zero amount of bytes */
michael@0 86 rv = PR_Malloc(bytes ? bytes : 1);
michael@0 87 }
michael@0 88 if (!rv) {
michael@0 89 ++port_allocFailures;
michael@0 90 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 91 }
michael@0 92 return rv;
michael@0 93 }
michael@0 94
michael@0 95 void *
michael@0 96 PORT_Realloc(void *oldptr, size_t bytes)
michael@0 97 {
michael@0 98 void *rv = NULL;
michael@0 99
michael@0 100 if (bytes <= MAX_SIZE) {
michael@0 101 rv = PR_Realloc(oldptr, bytes);
michael@0 102 }
michael@0 103 if (!rv) {
michael@0 104 ++port_allocFailures;
michael@0 105 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 106 }
michael@0 107 return rv;
michael@0 108 }
michael@0 109
michael@0 110 void *
michael@0 111 PORT_ZAlloc(size_t bytes)
michael@0 112 {
michael@0 113 void *rv = NULL;
michael@0 114
michael@0 115 if (bytes <= MAX_SIZE) {
michael@0 116 /* Always allocate a non-zero amount of bytes */
michael@0 117 rv = PR_Calloc(1, bytes ? bytes : 1);
michael@0 118 }
michael@0 119 if (!rv) {
michael@0 120 ++port_allocFailures;
michael@0 121 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 122 }
michael@0 123 return rv;
michael@0 124 }
michael@0 125
michael@0 126 void
michael@0 127 PORT_Free(void *ptr)
michael@0 128 {
michael@0 129 if (ptr) {
michael@0 130 PR_Free(ptr);
michael@0 131 }
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 PORT_ZFree(void *ptr, size_t len)
michael@0 136 {
michael@0 137 if (ptr) {
michael@0 138 memset(ptr, 0, len);
michael@0 139 PR_Free(ptr);
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 char *
michael@0 144 PORT_Strdup(const char *str)
michael@0 145 {
michael@0 146 size_t len = PORT_Strlen(str)+1;
michael@0 147 char *newstr;
michael@0 148
michael@0 149 newstr = (char *)PORT_Alloc(len);
michael@0 150 if (newstr) {
michael@0 151 PORT_Memcpy(newstr, str, len);
michael@0 152 }
michael@0 153 return newstr;
michael@0 154 }
michael@0 155
michael@0 156 void
michael@0 157 PORT_SetError(int value)
michael@0 158 {
michael@0 159 #ifdef DEBUG_jp96085
michael@0 160 PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
michael@0 161 #endif
michael@0 162 PR_SetError(value, 0);
michael@0 163 return;
michael@0 164 }
michael@0 165
michael@0 166 int
michael@0 167 PORT_GetError(void)
michael@0 168 {
michael@0 169 return(PR_GetError());
michael@0 170 }
michael@0 171
michael@0 172 /********************* Arena code follows *****************************
michael@0 173 * ArenaPools are like heaps. The memory in them consists of large blocks,
michael@0 174 * called arenas, which are allocated from the/a system heap. Inside an
michael@0 175 * ArenaPool, the arenas are organized as if they were in a stack. Newly
michael@0 176 * allocated arenas are "pushed" on that stack. When you attempt to
michael@0 177 * allocate memory from an ArenaPool, the code first looks to see if there
michael@0 178 * is enough unused space in the top arena on the stack to satisfy your
michael@0 179 * request, and if so, your request is satisfied from that arena.
michael@0 180 * Otherwise, a new arena is allocated (or taken from NSPR's list of freed
michael@0 181 * arenas) and pushed on to the stack. The new arena is always big enough
michael@0 182 * to satisfy the request, and is also at least a minimum size that is
michael@0 183 * established at the time that the ArenaPool is created.
michael@0 184 *
michael@0 185 * The ArenaMark function returns the address of a marker in the arena at
michael@0 186 * the top of the arena stack. It is the address of the place in the arena
michael@0 187 * on the top of the arena stack from which the next block of memory will
michael@0 188 * be allocated. Each ArenaPool has its own separate stack, and hence
michael@0 189 * marks are only relevant to the ArenaPool from which they are gotten.
michael@0 190 * Marks may be nested. That is, a thread can get a mark, and then get
michael@0 191 * another mark.
michael@0 192 *
michael@0 193 * It is intended that all the marks in an ArenaPool may only be owned by a
michael@0 194 * single thread. In DEBUG builds, this is enforced. In non-DEBUG builds,
michael@0 195 * it is not. In DEBUG builds, when a thread gets a mark from an
michael@0 196 * ArenaPool, no other thread may acquire a mark in that ArenaPool while
michael@0 197 * that mark exists, that is, until that mark is unmarked or released.
michael@0 198 * Therefore, it is important that every mark be unmarked or released when
michael@0 199 * the creating thread has no further need for exclusive ownership of the
michael@0 200 * right to manage the ArenaPool.
michael@0 201 *
michael@0 202 * The ArenaUnmark function discards the ArenaMark at the address given,
michael@0 203 * and all marks nested inside that mark (that is, acquired from that same
michael@0 204 * ArenaPool while that mark existed). It is an error for a thread other
michael@0 205 * than the mark's creator to try to unmark it. When a thread has unmarked
michael@0 206 * all its marks from an ArenaPool, then another thread is able to set
michael@0 207 * marks in that ArenaPool. ArenaUnmark does not deallocate (or "pop") any
michael@0 208 * memory allocated from the ArenaPool since the mark was created.
michael@0 209 *
michael@0 210 * ArenaRelease "pops" the stack back to the mark, deallocating all the
michael@0 211 * memory allocated from the arenas in the ArenaPool since that mark was
michael@0 212 * created, and removing any arenas from the ArenaPool that have no
michael@0 213 * remaining active allocations when that is done. It implicitly releases
michael@0 214 * any marks nested inside the mark being explicitly released. It is the
michael@0 215 * only operation, other than destroying the arenapool, that potentially
michael@0 216 * reduces the number of arenas on the stack. Otherwise, the stack grows
michael@0 217 * until the arenapool is destroyed, at which point all the arenas are
michael@0 218 * freed or returned to a "free arena list", depending on their sizes.
michael@0 219 */
michael@0 220 PLArenaPool *
michael@0 221 PORT_NewArena(unsigned long chunksize)
michael@0 222 {
michael@0 223 PORTArenaPool *pool;
michael@0 224
michael@0 225 if (chunksize > MAX_SIZE) {
michael@0 226 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 227 return NULL;
michael@0 228 }
michael@0 229 pool = PORT_ZNew(PORTArenaPool);
michael@0 230 if (!pool) {
michael@0 231 return NULL;
michael@0 232 }
michael@0 233 pool->magic = ARENAPOOL_MAGIC;
michael@0 234 pool->lock = PZ_NewLock(nssILockArena);
michael@0 235 if (!pool->lock) {
michael@0 236 ++port_allocFailures;
michael@0 237 PORT_Free(pool);
michael@0 238 return NULL;
michael@0 239 }
michael@0 240 PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
michael@0 241 return(&pool->arena);
michael@0 242 }
michael@0 243
michael@0 244 void *
michael@0 245 PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
michael@0 246 {
michael@0 247 void *p = NULL;
michael@0 248
michael@0 249 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 250
michael@0 251 if (size <= 0) {
michael@0 252 size = 1;
michael@0 253 }
michael@0 254
michael@0 255 if (size > MAX_SIZE) {
michael@0 256 /* you lose. */
michael@0 257 } else
michael@0 258 /* Is it one of ours? Assume so and check the magic */
michael@0 259 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 260 PZ_Lock(pool->lock);
michael@0 261 #ifdef THREADMARK
michael@0 262 /* Most likely one of ours. Is there a thread id? */
michael@0 263 if (pool->marking_thread &&
michael@0 264 pool->marking_thread != PR_GetCurrentThread() ) {
michael@0 265 /* Another thread holds a mark in this arena */
michael@0 266 PZ_Unlock(pool->lock);
michael@0 267 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 268 PORT_Assert(0);
michael@0 269 return NULL;
michael@0 270 } /* tid != null */
michael@0 271 #endif /* THREADMARK */
michael@0 272 PL_ARENA_ALLOCATE(p, arena, size);
michael@0 273 PZ_Unlock(pool->lock);
michael@0 274 } else {
michael@0 275 PL_ARENA_ALLOCATE(p, arena, size);
michael@0 276 }
michael@0 277
michael@0 278 if (!p) {
michael@0 279 ++port_allocFailures;
michael@0 280 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 281 }
michael@0 282
michael@0 283 return(p);
michael@0 284 }
michael@0 285
michael@0 286 void *
michael@0 287 PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
michael@0 288 {
michael@0 289 void *p;
michael@0 290
michael@0 291 if (size <= 0)
michael@0 292 size = 1;
michael@0 293
michael@0 294 p = PORT_ArenaAlloc(arena, size);
michael@0 295
michael@0 296 if (p) {
michael@0 297 PORT_Memset(p, 0, size);
michael@0 298 }
michael@0 299
michael@0 300 return(p);
michael@0 301 }
michael@0 302
michael@0 303 /*
michael@0 304 * If zero is true, zeroize the arena memory before freeing it.
michael@0 305 */
michael@0 306 void
michael@0 307 PORT_FreeArena(PLArenaPool *arena, PRBool zero)
michael@0 308 {
michael@0 309 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 310 PRLock * lock = (PRLock *)0;
michael@0 311 size_t len = sizeof *arena;
michael@0 312 static PRBool checkedEnv = PR_FALSE;
michael@0 313 static PRBool doFreeArenaPool = PR_FALSE;
michael@0 314
michael@0 315 if (!pool)
michael@0 316 return;
michael@0 317 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 318 len = sizeof *pool;
michael@0 319 lock = pool->lock;
michael@0 320 PZ_Lock(lock);
michael@0 321 }
michael@0 322 if (!checkedEnv) {
michael@0 323 /* no need for thread protection here */
michael@0 324 doFreeArenaPool = (PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
michael@0 325 checkedEnv = PR_TRUE;
michael@0 326 }
michael@0 327 if (zero) {
michael@0 328 PL_ClearArenaPool(arena, 0);
michael@0 329 }
michael@0 330 if (doFreeArenaPool) {
michael@0 331 PL_FreeArenaPool(arena);
michael@0 332 } else {
michael@0 333 PL_FinishArenaPool(arena);
michael@0 334 }
michael@0 335 PORT_ZFree(arena, len);
michael@0 336 if (lock) {
michael@0 337 PZ_Unlock(lock);
michael@0 338 PZ_DestroyLock(lock);
michael@0 339 }
michael@0 340 }
michael@0 341
michael@0 342 void *
michael@0 343 PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
michael@0 344 {
michael@0 345 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 346 PORT_Assert(newsize >= oldsize);
michael@0 347
michael@0 348 if (newsize > MAX_SIZE) {
michael@0 349 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 350 return NULL;
michael@0 351 }
michael@0 352
michael@0 353 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 354 PZ_Lock(pool->lock);
michael@0 355 /* Do we do a THREADMARK check here? */
michael@0 356 PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
michael@0 357 PZ_Unlock(pool->lock);
michael@0 358 } else {
michael@0 359 PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
michael@0 360 }
michael@0 361
michael@0 362 return(ptr);
michael@0 363 }
michael@0 364
michael@0 365 void *
michael@0 366 PORT_ArenaMark(PLArenaPool *arena)
michael@0 367 {
michael@0 368 void * result;
michael@0 369
michael@0 370 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 371 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 372 PZ_Lock(pool->lock);
michael@0 373 #ifdef THREADMARK
michael@0 374 {
michael@0 375 threadmark_mark *tm, **pw;
michael@0 376 PRThread * currentThread = PR_GetCurrentThread();
michael@0 377
michael@0 378 if (! pool->marking_thread ) {
michael@0 379 /* First mark */
michael@0 380 pool->marking_thread = currentThread;
michael@0 381 } else if (currentThread != pool->marking_thread ) {
michael@0 382 PZ_Unlock(pool->lock);
michael@0 383 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 384 PORT_Assert(0);
michael@0 385 return NULL;
michael@0 386 }
michael@0 387
michael@0 388 result = PL_ARENA_MARK(arena);
michael@0 389 PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
michael@0 390 if (!tm) {
michael@0 391 PZ_Unlock(pool->lock);
michael@0 392 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 393 return NULL;
michael@0 394 }
michael@0 395
michael@0 396 tm->mark = result;
michael@0 397 tm->next = (threadmark_mark *)NULL;
michael@0 398
michael@0 399 pw = &pool->first_mark;
michael@0 400 while( *pw ) {
michael@0 401 pw = &(*pw)->next;
michael@0 402 }
michael@0 403
michael@0 404 *pw = tm;
michael@0 405 }
michael@0 406 #else /* THREADMARK */
michael@0 407 result = PL_ARENA_MARK(arena);
michael@0 408 #endif /* THREADMARK */
michael@0 409 PZ_Unlock(pool->lock);
michael@0 410 } else {
michael@0 411 /* a "pure" NSPR arena */
michael@0 412 result = PL_ARENA_MARK(arena);
michael@0 413 }
michael@0 414 return result;
michael@0 415 }
michael@0 416
michael@0 417 /*
michael@0 418 * This function accesses the internals of PLArena, which is why it needs
michael@0 419 * to use the NSPR internal macro PL_MAKE_MEM_UNDEFINED before the memset
michael@0 420 * calls.
michael@0 421 *
michael@0 422 * We should move this function to NSPR as PL_ClearArenaAfterMark or add
michael@0 423 * a PL_ARENA_CLEAR_AND_RELEASE macro.
michael@0 424 *
michael@0 425 * TODO: remove the #ifdef PL_MAKE_MEM_UNDEFINED tests when NSPR 4.10+ is
michael@0 426 * widely available.
michael@0 427 */
michael@0 428 static void
michael@0 429 port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
michael@0 430 {
michael@0 431 PLArena *a = arena->current;
michael@0 432 if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
michael@0 433 /* fast path: mark falls in the current arena */
michael@0 434 #ifdef PL_MAKE_MEM_UNDEFINED
michael@0 435 PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
michael@0 436 #endif
michael@0 437 memset(mark, 0, a->avail - (PRUword)mark);
michael@0 438 } else {
michael@0 439 /* slow path: need to find the arena that mark falls in */
michael@0 440 for (a = arena->first.next; a; a = a->next) {
michael@0 441 PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
michael@0 442 if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
michael@0 443 #ifdef PL_MAKE_MEM_UNDEFINED
michael@0 444 PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
michael@0 445 #endif
michael@0 446 memset(mark, 0, a->avail - (PRUword)mark);
michael@0 447 a = a->next;
michael@0 448 break;
michael@0 449 }
michael@0 450 }
michael@0 451 for (; a; a = a->next) {
michael@0 452 PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
michael@0 453 #ifdef PL_MAKE_MEM_UNDEFINED
michael@0 454 PL_MAKE_MEM_UNDEFINED((void *)a->base, a->avail - a->base);
michael@0 455 #endif
michael@0 456 memset((void *)a->base, 0, a->avail - a->base);
michael@0 457 }
michael@0 458 }
michael@0 459 }
michael@0 460
michael@0 461 static void
michael@0 462 port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
michael@0 463 {
michael@0 464 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 465 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 466 PZ_Lock(pool->lock);
michael@0 467 #ifdef THREADMARK
michael@0 468 {
michael@0 469 threadmark_mark **pw, *tm;
michael@0 470
michael@0 471 if (PR_GetCurrentThread() != pool->marking_thread ) {
michael@0 472 PZ_Unlock(pool->lock);
michael@0 473 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 474 PORT_Assert(0);
michael@0 475 return /* no error indication available */ ;
michael@0 476 }
michael@0 477
michael@0 478 pw = &pool->first_mark;
michael@0 479 while( *pw && (mark != (*pw)->mark) ) {
michael@0 480 pw = &(*pw)->next;
michael@0 481 }
michael@0 482
michael@0 483 if (! *pw ) {
michael@0 484 /* bad mark */
michael@0 485 PZ_Unlock(pool->lock);
michael@0 486 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 487 PORT_Assert(0);
michael@0 488 return /* no error indication available */ ;
michael@0 489 }
michael@0 490
michael@0 491 tm = *pw;
michael@0 492 *pw = (threadmark_mark *)NULL;
michael@0 493
michael@0 494 if (zero) {
michael@0 495 port_ArenaZeroAfterMark(arena, mark);
michael@0 496 }
michael@0 497 PL_ARENA_RELEASE(arena, mark);
michael@0 498
michael@0 499 if (! pool->first_mark ) {
michael@0 500 pool->marking_thread = (PRThread *)NULL;
michael@0 501 }
michael@0 502 }
michael@0 503 #else /* THREADMARK */
michael@0 504 if (zero) {
michael@0 505 port_ArenaZeroAfterMark(arena, mark);
michael@0 506 }
michael@0 507 PL_ARENA_RELEASE(arena, mark);
michael@0 508 #endif /* THREADMARK */
michael@0 509 PZ_Unlock(pool->lock);
michael@0 510 } else {
michael@0 511 if (zero) {
michael@0 512 port_ArenaZeroAfterMark(arena, mark);
michael@0 513 }
michael@0 514 PL_ARENA_RELEASE(arena, mark);
michael@0 515 }
michael@0 516 }
michael@0 517
michael@0 518 void
michael@0 519 PORT_ArenaRelease(PLArenaPool *arena, void *mark)
michael@0 520 {
michael@0 521 port_ArenaRelease(arena, mark, PR_FALSE);
michael@0 522 }
michael@0 523
michael@0 524 /*
michael@0 525 * Zeroize the arena memory before releasing it.
michael@0 526 */
michael@0 527 void
michael@0 528 PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
michael@0 529 {
michael@0 530 port_ArenaRelease(arena, mark, PR_TRUE);
michael@0 531 }
michael@0 532
michael@0 533 void
michael@0 534 PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
michael@0 535 {
michael@0 536 #ifdef THREADMARK
michael@0 537 PORTArenaPool *pool = (PORTArenaPool *)arena;
michael@0 538 if (ARENAPOOL_MAGIC == pool->magic ) {
michael@0 539 threadmark_mark **pw, *tm;
michael@0 540
michael@0 541 PZ_Lock(pool->lock);
michael@0 542
michael@0 543 if (PR_GetCurrentThread() != pool->marking_thread ) {
michael@0 544 PZ_Unlock(pool->lock);
michael@0 545 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 546 PORT_Assert(0);
michael@0 547 return /* no error indication available */ ;
michael@0 548 }
michael@0 549
michael@0 550 pw = &pool->first_mark;
michael@0 551 while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
michael@0 552 pw = &(*pw)->next;
michael@0 553 }
michael@0 554
michael@0 555 if ((threadmark_mark *)NULL == *pw ) {
michael@0 556 /* bad mark */
michael@0 557 PZ_Unlock(pool->lock);
michael@0 558 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 559 PORT_Assert(0);
michael@0 560 return /* no error indication available */ ;
michael@0 561 }
michael@0 562
michael@0 563 tm = *pw;
michael@0 564 *pw = (threadmark_mark *)NULL;
michael@0 565
michael@0 566 if (! pool->first_mark ) {
michael@0 567 pool->marking_thread = (PRThread *)NULL;
michael@0 568 }
michael@0 569
michael@0 570 PZ_Unlock(pool->lock);
michael@0 571 }
michael@0 572 #endif /* THREADMARK */
michael@0 573 }
michael@0 574
michael@0 575 char *
michael@0 576 PORT_ArenaStrdup(PLArenaPool *arena, const char *str) {
michael@0 577 int len = PORT_Strlen(str)+1;
michael@0 578 char *newstr;
michael@0 579
michael@0 580 newstr = (char*)PORT_ArenaAlloc(arena,len);
michael@0 581 if (newstr) {
michael@0 582 PORT_Memcpy(newstr,str,len);
michael@0 583 }
michael@0 584 return newstr;
michael@0 585 }
michael@0 586
michael@0 587 /********************** end of arena functions ***********************/
michael@0 588
michael@0 589 /****************** unicode conversion functions ***********************/
michael@0 590 /*
michael@0 591 * NOTE: These conversion functions all assume that the multibyte
michael@0 592 * characters are going to be in NETWORK BYTE ORDER, not host byte
michael@0 593 * order. This is because the only time we deal with UCS-2 and UCS-4
michael@0 594 * are when the data was received from or is going to be sent out
michael@0 595 * over the wire (in, e.g. certificates).
michael@0 596 */
michael@0 597
michael@0 598 void
michael@0 599 PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
michael@0 600 {
michael@0 601 ucs4Utf8ConvertFunc = convFunc;
michael@0 602 }
michael@0 603
michael@0 604 void
michael@0 605 PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
michael@0 606 {
michael@0 607 ucs2AsciiConvertFunc = convFunc;
michael@0 608 }
michael@0 609
michael@0 610 void
michael@0 611 PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
michael@0 612 {
michael@0 613 ucs2Utf8ConvertFunc = convFunc;
michael@0 614 }
michael@0 615
michael@0 616 PRBool
michael@0 617 PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
michael@0 618 unsigned int inBufLen, unsigned char *outBuf,
michael@0 619 unsigned int maxOutBufLen, unsigned int *outBufLen)
michael@0 620 {
michael@0 621 if(!ucs4Utf8ConvertFunc) {
michael@0 622 return sec_port_ucs4_utf8_conversion_function(toUnicode,
michael@0 623 inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
michael@0 624 }
michael@0 625
michael@0 626 return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
michael@0 627 maxOutBufLen, outBufLen);
michael@0 628 }
michael@0 629
michael@0 630 PRBool
michael@0 631 PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
michael@0 632 unsigned int inBufLen, unsigned char *outBuf,
michael@0 633 unsigned int maxOutBufLen, unsigned int *outBufLen)
michael@0 634 {
michael@0 635 if(!ucs2Utf8ConvertFunc) {
michael@0 636 return sec_port_ucs2_utf8_conversion_function(toUnicode,
michael@0 637 inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
michael@0 638 }
michael@0 639
michael@0 640 return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
michael@0 641 maxOutBufLen, outBufLen);
michael@0 642 }
michael@0 643
michael@0 644 PRBool
michael@0 645 PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
michael@0 646 unsigned int inBufLen, unsigned char *outBuf,
michael@0 647 unsigned int maxOutBufLen, unsigned int *outBufLen)
michael@0 648 {
michael@0 649 return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
michael@0 650 outBuf, maxOutBufLen, outBufLen);
michael@0 651 }
michael@0 652
michael@0 653 PRBool
michael@0 654 PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
michael@0 655 unsigned int inBufLen, unsigned char *outBuf,
michael@0 656 unsigned int maxOutBufLen, unsigned int *outBufLen,
michael@0 657 PRBool swapBytes)
michael@0 658 {
michael@0 659 if(!ucs2AsciiConvertFunc) {
michael@0 660 return PR_FALSE;
michael@0 661 }
michael@0 662
michael@0 663 return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
michael@0 664 maxOutBufLen, outBufLen, swapBytes);
michael@0 665 }
michael@0 666
michael@0 667
michael@0 668 /* Portable putenv. Creates/replaces an environment variable of the form
michael@0 669 * envVarName=envValue
michael@0 670 */
michael@0 671 int
michael@0 672 NSS_PutEnv(const char * envVarName, const char * envValue)
michael@0 673 {
michael@0 674 SECStatus result = SECSuccess;
michael@0 675 char * encoded;
michael@0 676 int putEnvFailed;
michael@0 677 #ifdef _WIN32
michael@0 678 PRBool setOK;
michael@0 679
michael@0 680 setOK = SetEnvironmentVariable(envVarName, envValue);
michael@0 681 if (!setOK) {
michael@0 682 SET_ERROR_CODE
michael@0 683 return SECFailure;
michael@0 684 }
michael@0 685 #endif
michael@0 686
michael@0 687 encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
michael@0 688 strcpy(encoded, envVarName);
michael@0 689 strcat(encoded, "=");
michael@0 690 strcat(encoded, envValue);
michael@0 691
michael@0 692 putEnvFailed = putenv(encoded); /* adopt. */
michael@0 693 if (putEnvFailed) {
michael@0 694 SET_ERROR_CODE
michael@0 695 result = SECFailure;
michael@0 696 PORT_Free(encoded);
michael@0 697 }
michael@0 698 return result;
michael@0 699 }
michael@0 700
michael@0 701 /*
michael@0 702 * Perform a constant-time compare of two memory regions. The return value is
michael@0 703 * 0 if the memory regions are equal and non-zero otherwise.
michael@0 704 */
michael@0 705 int
michael@0 706 NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
michael@0 707 {
michael@0 708 const unsigned char *a = (const unsigned char*) ia;
michael@0 709 const unsigned char *b = (const unsigned char*) ib;
michael@0 710 size_t i;
michael@0 711 unsigned char r = 0;
michael@0 712
michael@0 713 for (i = 0; i < n; ++i) {
michael@0 714 r |= *a++ ^ *b++;
michael@0 715 }
michael@0 716
michael@0 717 return r;
michael@0 718 }

mercurial