Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: mozilla/security/nss/lib/util/secport.c

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

Powered by Google App Engine
This is Rietveld 408576698