--- a/security/nss/lib/certdb/alg1485.c
+++ b/security/nss/lib/certdb/alg1485.c
@@ -1393,60 +1393,61 @@ appendItemToBuf(char* dest, SECItem* src
** This function is intended to be internal to NSS.
*/
char*
cert_GetCertificateEmailAddresses(CERTCertificate* cert)
{
char* rawEmailAddr = NULL;
char* addrBuf = NULL;
char* pBuf = NULL;
- PLArenaPool* tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ PORTCheapArenaPool tmpArena;
PRUint32 maxLen = 0;
PRInt32 finalLen = 0;
SECStatus rv;
SECItem subAltName;
- if (!tmpArena)
- return addrBuf;
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
subAltName.data = NULL;
maxLen = cert->derCert.len;
PORT_Assert(maxLen);
if (!maxLen)
maxLen = 2000; /* a guess, should never happen */
- pBuf = addrBuf = (char*)PORT_ArenaZAlloc(tmpArena, maxLen + 1);
+ pBuf = addrBuf = (char*)PORT_ArenaZAlloc(&tmpArena.arena, maxLen + 1);
if (!addrBuf)
goto loser;
- rawEmailAddr =
- CERT_GetNameElement(tmpArena, &cert->subject, SEC_OID_PKCS9_EMAIL_ADDRESS);
+ rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
+ SEC_OID_PKCS9_EMAIL_ADDRESS);
pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
- rawEmailAddr =
- CERT_GetNameElement(tmpArena, &cert->subject, SEC_OID_RFC1274_MAIL);
+ rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
+ SEC_OID_RFC1274_MAIL);
pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName);
if (rv == SECSuccess && subAltName.data) {
CERTGeneralName* nameList = NULL;
- if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) {
+ if (!!(nameList = CERT_DecodeAltNameExtension(&tmpArena.arena, &subAltName))) {
CERTGeneralName* current = nameList;
do {
if (current->type == certDirectoryName) {
rawEmailAddr =
- CERT_GetNameElement(tmpArena, ¤t->name.directoryName,
+ CERT_GetNameElement(&tmpArena.arena,
+ ¤t->name.directoryName,
SEC_OID_PKCS9_EMAIL_ADDRESS);
pBuf =
appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
rawEmailAddr =
- CERT_GetNameElement(
- tmpArena, ¤t->name.directoryName, SEC_OID_RFC1274_MAIL);
+ CERT_GetNameElement(&tmpArena.arena,
+ ¤t->name.directoryName,
+ SEC_OID_RFC1274_MAIL);
pBuf =
appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
} else if (current->type == certRFC822Name) {
pBuf =
appendItemToBuf(pBuf, ¤t->name.other, &maxLen);
}
current = CERT_GetNextGeneralName(current);
} while (current != nameList);
@@ -1459,18 +1460,17 @@ cert_GetCertificateEmailAddresses(CERTCe
pBuf = NULL;
if (finalLen > 1) {
pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
if (pBuf) {
PORT_Memcpy(pBuf, addrBuf, finalLen);
}
}
loser:
- if (tmpArena)
- PORT_FreeArena(tmpArena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return pBuf;
}
/* returns pointer to storage in cert's arena. Storage remains valid
** as long as cert's reference count doesn't go to zero.
** Caller should strdup or otherwise copy.
*/
--- a/security/nss/lib/certdb/certdb.c
+++ b/security/nss/lib/certdb/certdb.c
@@ -252,99 +252,89 @@ loser:
PORT_FreeArena(arena, PR_FALSE);
return (SECFailure);
}
SECStatus
CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
{
int rv;
- PLArenaPool *arena;
+ PORTCheapArenaPool tmpArena;
CERTSignedData sd;
void *tmpptr;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
-
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
+ derCert);
if (rv) {
goto loser;
}
PORT_Memset(derName, 0, sizeof(SECItem));
- rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertIssuerTemplate,
- &sd.data);
-
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
+ SEC_CertIssuerTemplate, &sd.data);
if (rv) {
goto loser;
}
tmpptr = derName->data;
derName->data = (unsigned char *)PORT_Alloc(derName->len);
if (derName->data == NULL) {
goto loser;
}
PORT_Memcpy(derName->data, tmpptr, derName->len);
- PORT_FreeArena(arena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return (SECSuccess);
loser:
- PORT_FreeArena(arena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return (SECFailure);
}
SECStatus
CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
{
int rv;
- PLArenaPool *arena;
+ PORTCheapArenaPool tmpArena;
CERTSignedData sd;
void *tmpptr;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
-
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
+ derCert);
if (rv) {
goto loser;
}
PORT_Memset(derName, 0, sizeof(SECItem));
- rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSerialNumberTemplate,
- &sd.data);
-
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
+ SEC_CertSerialNumberTemplate, &sd.data);
if (rv) {
goto loser;
}
tmpptr = derName->data;
derName->data = (unsigned char *)PORT_Alloc(derName->len);
if (derName->data == NULL) {
goto loser;
}
PORT_Memcpy(derName->data, tmpptr, derName->len);
- PORT_FreeArena(arena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return (SECSuccess);
loser:
- PORT_FreeArena(arena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return (SECFailure);
}
/*
* Generate a database key, based on serial number and issuer, from a
* DER certificate.
*/
SECStatus
--- a/security/nss/lib/certdb/certv3.c
+++ b/security/nss/lib/certdb/certv3.c
@@ -124,28 +124,25 @@ CERT_FindSubjectKeyIDExtension(CERTCerti
SECStatus rv;
SECItem encodedValue = { siBuffer, NULL, 0 };
SECItem decodedValue = { siBuffer, NULL, 0 };
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID,
&encodedValue);
if (rv == SECSuccess) {
- PLArenaPool *tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (tmpArena) {
- rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue,
- SEC_ASN1_GET(SEC_OctetStringTemplate),
- &encodedValue);
- if (rv == SECSuccess) {
- rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
- }
- PORT_FreeArena(tmpArena, PR_FALSE);
- } else {
- rv = SECFailure;
+ PORTCheapArenaPool tmpArena;
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodedValue,
+ SEC_ASN1_GET(SEC_OctetStringTemplate),
+ &encodedValue);
+ if (rv == SECSuccess) {
+ rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
}
+ PORT_DestroyCheapArena(&tmpArena);
}
SECITEM_FreeItem(&encodedValue, PR_FALSE);
return rv;
}
SECStatus
CERT_FindBasicConstraintExten(CERTCertificate *cert,
CERTBasicConstraints *value)
--- a/security/nss/lib/certdb/certxutl.c
+++ b/security/nss/lib/certdb/certxutl.c
@@ -389,34 +389,31 @@ CERT_MergeExtensions(void *exthandle, CE
* get the value of the Netscape Certificate Type Extension
*/
SECStatus
CERT_FindBitStringExtension(CERTCertExtension **extensions, int tag,
SECItem *retItem)
{
SECItem wrapperItem, tmpItem = { siBuffer, 0 };
SECStatus rv;
- PLArenaPool *arena = NULL;
+ PORTCheapArenaPool tmpArena;
wrapperItem.data = NULL;
tmpItem.data = NULL;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
rv = cert_FindExtension(extensions, tag, &wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
- rv = SEC_QuickDERDecodeItem(
- arena, &tmpItem, SEC_ASN1_GET(SEC_BitStringTemplate), &wrapperItem);
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &tmpItem,
+ SEC_ASN1_GET(SEC_BitStringTemplate),
+ &wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
retItem->data = (unsigned char *)PORT_Alloc((tmpItem.len + 7) >> 3);
if (retItem->data == NULL) {
goto loser;
@@ -427,19 +424,17 @@ CERT_FindBitStringExtension(CERTCertExte
rv = SECSuccess;
goto done;
loser:
rv = SECFailure;
done:
- if (arena) {
- PORT_FreeArena(arena, PR_FALSE);
- }
+ PORT_DestroyCheapArena(&tmpArena);
if (wrapperItem.data) {
PORT_Free(wrapperItem.data);
}
return (rv);
}
--- a/security/nss/lib/certdb/secname.c
+++ b/security/nss/lib/certdb/secname.c
@@ -603,17 +603,17 @@ CERT_CompareName(const CERTName *a, cons
/* Moved from certhtml.c */
SECItem *
CERT_DecodeAVAValue(const SECItem *derAVAValue)
{
SECItem *retItem;
const SEC_ASN1Template *theTemplate = NULL;
enum { conv_none, conv_ucs4, conv_ucs2, conv_iso88591 } convert = conv_none;
SECItem avaValue = { siBuffer, 0 };
- PLArenaPool *newarena = NULL;
+ PORTCheapArenaPool tmpArena;
if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
switch (derAVAValue->data[0]) {
case SEC_ASN1_UNIVERSAL_STRING:
@@ -643,66 +643,63 @@ CERT_DecodeAVAValue(const SECItem *derAV
theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
break;
default:
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
PORT_Memset(&avaValue, 0, sizeof(SECItem));
- newarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!newarena) {
- return NULL;
- }
- if (SEC_QuickDERDecodeItem(newarena, &avaValue, theTemplate, derAVAValue) !=
- SECSuccess) {
- PORT_FreeArena(newarena, PR_FALSE);
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+ if (SEC_QuickDERDecodeItem(&tmpArena.arena, &avaValue, theTemplate,
+ derAVAValue) != SECSuccess) {
+ PORT_DestroyCheapArena(&tmpArena);
return NULL;
}
if (convert != conv_none) {
unsigned int utf8ValLen = avaValue.len * 3;
unsigned char *utf8Val =
- (unsigned char *)PORT_ArenaZAlloc(newarena, utf8ValLen);
+ (unsigned char *)PORT_ArenaZAlloc(&tmpArena.arena, utf8ValLen);
switch (convert) {
case conv_ucs4:
if (avaValue.len % 4 != 0 ||
!PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data,
avaValue.len, utf8Val, utf8ValLen,
&utf8ValLen)) {
- PORT_FreeArena(newarena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_ucs2:
if (avaValue.len % 2 != 0 ||
!PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data,
avaValue.len, utf8Val, utf8ValLen,
&utf8ValLen)) {
- PORT_FreeArena(newarena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_iso88591:
if (!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len,
utf8Val, utf8ValLen,
&utf8ValLen)) {
- PORT_FreeArena(newarena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_none:
PORT_Assert(0); /* not reached */
break;
}
avaValue.data = utf8Val;
avaValue.len = utf8ValLen;
}
retItem = SECITEM_DupItem(&avaValue);
- PORT_FreeArena(newarena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return retItem;
}
--- a/security/nss/lib/certdb/xbsconst.c
+++ b/security/nss/lib/certdb/xbsconst.c
@@ -88,34 +88,30 @@ CERT_EncodeBasicConstraintValue(PLArenaP
return (rv);
}
SECStatus
CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value,
const SECItem *encodedValue)
{
EncodedContext decodeContext;
- PLArenaPool *our_pool;
+ PORTCheapArenaPool tmpArena;
SECStatus rv = SECSuccess;
do {
PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
/* initialize the value just in case we got "0x30 00", or when the
pathLenConstraint is omitted.
*/
decodeContext.isCA.data = &hexFalse;
decodeContext.isCA.len = 1;
- our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
- if (our_pool == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- GEN_BREAK(SECFailure);
- }
+ PORT_InitCheapArena(&tmpArena, SEC_ASN1_DEFAULT_ARENA_SIZE);
- rv = SEC_QuickDERDecodeItem(our_pool, &decodeContext,
+ rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodeContext,
CERTBasicConstraintsTemplate, encodedValue);
if (rv == SECFailure)
break;
value->isCA = decodeContext.isCA.data
? (PRBool)(decodeContext.isCA.data[0] != 0)
: PR_FALSE;
if (decodeContext.pathLenConstraint.data == NULL) {
@@ -135,13 +131,13 @@ CERT_DecodeBasicConstraintValue(CERTBasi
value->pathLenConstraint = len;
} else {
/* here we get an error where the subject is not a CA, but
the pathLenConstraint is set */
PORT_SetError(SEC_ERROR_BAD_DER);
GEN_BREAK(SECFailure);
break;
}
+ } while (0);
- } while (0);
- PORT_FreeArena(our_pool, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return (rv);
}
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -1809,48 +1809,47 @@ PK11_MatchItem(PK11SlotInfo *slot, CK_OB
{ CKA_ID, NULL, 0 },
{ CKA_CLASS, NULL, 0 }
};
/* if you change the array, change the variable below as well */
CK_ATTRIBUTE *keyclass = &theTemplate[1];
int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
/* if you change the array, change the variable below as well */
CK_OBJECT_HANDLE peerID;
- PLArenaPool *arena;
+ PORTCheapArenaPool tmpArena;
CK_RV crv;
/* now we need to create space for the public key */
- arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) return CK_INVALID_HANDLE;
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
- crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize);
+ crv = PK11_GetAttributes(&tmpArena.arena,slot,searchID,theTemplate,tsize);
if (crv != CKR_OK) {
- PORT_FreeArena(arena,PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
PORT_SetError( PK11_MapError(crv) );
return CK_INVALID_HANDLE;
}
if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
- PORT_FreeArena(arena,PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
if (matchclass == CKO_CERTIFICATE)
PORT_SetError(SEC_ERROR_BAD_KEY);
else
PORT_SetError(SEC_ERROR_NO_KEY);
return CK_INVALID_HANDLE;
}
/*
* issue the find
*/
*(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
- PORT_FreeArena(arena,PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return peerID;
}
/*
* count the number of objects that match the template.
*/
int
--- a/security/nss/lib/softoken/legacydb/pcertdb.c
+++ b/security/nss/lib/softoken/legacydb/pcertdb.c
@@ -2553,66 +2553,62 @@ loser:
}
/*
* Read the subject entry
*/
static certDBEntrySubject *
ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
{
+ /* |arena| isn't function-bounded, so cannot be a PORTCheapArenaPool. */
PLArenaPool *arena = NULL;
- PLArenaPool *tmparena = NULL;
+ PORTCheapArenaPool tmpArena;
+
certDBEntrySubject *entry;
SECItem dbkey;
SECItem dbentry;
SECStatus rv;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if ( arena == NULL ) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser;
}
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+
entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
sizeof(certDBEntrySubject));
if ( entry == NULL ) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser;
}
entry->common.arena = arena;
entry->common.type = certDBEntryTypeSubject;
- rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey);
+ rv = EncodeDBSubjectKey(derSubject, &tmpArena.arena, &dbkey);
if ( rv != SECSuccess ) {
goto loser;
}
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
+ rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, &tmpArena.arena);
if ( rv == SECFailure ) {
goto loser;
}
rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
if ( rv == SECFailure ) {
goto loser;
}
- PORT_FreeArena(tmparena, PR_FALSE);
+ PORT_DestroyCheapArena(&tmpArena);
return(entry);
loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
+ PORT_DestroyCheapArena(&tmpArena);
if ( arena ) {
PORT_FreeArena(arena, PR_FALSE);
}
return(NULL);
}
/*
--- a/security/nss/lib/util/nssutil.def
+++ b/security/nss/lib/util/nssutil.def
@@ -278,8 +278,15 @@ SECITEM_ZfreeArray;
;+ *;
;+};
;+NSSUTIL_3.21 { # NSS Utilities 3.21 release
;+ global:
NSSUTIL_ArgParseModuleSpecEx;
;+ local:
;+ *;
;+};
+;+NSSUTIL_3.24 { # NSS Utilities 3.24 release
+;+ global:
+PORT_InitCheapArena;
+PORT_DestroyCheapArena;
+;+ local:
+;+ *;
+;+};
--- a/security/nss/lib/util/secport.c
+++ b/security/nss/lib/util/secport.c
@@ -14,16 +14,17 @@
#include "prmem.h"
#include "prerror.h"
#include "plarena.h"
#include "secerr.h"
#include "prmon.h"
#include "nssilock.h"
#include "secport.h"
#include "prenv.h"
+#include "prinit.h"
#ifdef DEBUG
#define THREADMARK
#endif /* DEBUG */
#ifdef THREADMARK
#include "prthread.h"
#endif /* THREADMARK */
@@ -42,16 +43,18 @@ typedef struct threadmark_mark_str {
void *mark;
} threadmark_mark;
#endif /* THREADMARK */
/* The value of this magic must change each time PORTArenaPool changes. */
#define ARENAPOOL_MAGIC 0xB8AC9BDF
+#define CHEAP_ARENAPOOL_MAGIC 0x3F16BB09
+
typedef struct PORTArenaPool_str {
PLArenaPool arena;
PRUint32 magic;
PRLock * lock;
#ifdef THREADMARK
PRThread *marking_thread;
threadmark_mark *first_mark;
#endif
@@ -229,16 +232,23 @@ PORT_NewArena(unsigned long chunksize)
if (!pool->lock) {
PORT_Free(pool);
return NULL;
}
PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
return(&pool->arena);
}
+void
+PORT_InitCheapArena(PORTCheapArenaPool* pool, unsigned long chunksize)
+{
+ pool->magic = CHEAP_ARENAPOOL_MAGIC;
+ PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
+}
+
void *
PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
{
void *p = NULL;
PORTArenaPool *pool = (PORTArenaPool *)arena;
if (size <= 0) {
@@ -287,55 +297,70 @@ PORT_ArenaZAlloc(PLArenaPool *arena, siz
if (p) {
PORT_Memset(p, 0, size);
}
return(p);
}
+static PRCallOnceType setupUseFreeListOnce;
+static PRBool useFreeList;
+
+static PRStatus
+SetupUseFreeList(void)
+{
+ useFreeList = (PR_GetEnvSecure("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
+ return PR_SUCCESS;
+}
+
/*
* If zero is true, zeroize the arena memory before freeing it.
*/
void
PORT_FreeArena(PLArenaPool *arena, PRBool zero)
{
PORTArenaPool *pool = (PORTArenaPool *)arena;
PRLock * lock = (PRLock *)0;
size_t len = sizeof *arena;
- static PRBool checkedEnv = PR_FALSE;
- static PRBool doFreeArenaPool = PR_FALSE;
if (!pool)
return;
if (ARENAPOOL_MAGIC == pool->magic ) {
len = sizeof *pool;
lock = pool->lock;
PZ_Lock(lock);
}
- if (!checkedEnv) {
- /* no need for thread protection here */
- doFreeArenaPool = (PR_GetEnvSecure("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
- checkedEnv = PR_TRUE;
- }
if (zero) {
PL_ClearArenaPool(arena, 0);
}
- if (doFreeArenaPool) {
+ PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList);
+ if (useFreeList) {
PL_FreeArenaPool(arena);
} else {
PL_FinishArenaPool(arena);
}
PORT_ZFree(arena, len);
if (lock) {
PZ_Unlock(lock);
PZ_DestroyLock(lock);
}
}
+void
+PORT_DestroyCheapArena(PORTCheapArenaPool* pool)
+{
+ PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList);
+ if (useFreeList) {
+ PL_FreeArenaPool(&pool->arena);
+ } else {
+ PL_FinishArenaPool(&pool->arena);
+ }
+}
+
void *
PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
{
PORTArenaPool *pool = (PORTArenaPool *)arena;
PORT_Assert(newsize >= oldsize);
if (newsize > MAX_SIZE) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
--- a/security/nss/lib/util/secport.h
+++ b/security/nss/lib/util/secport.h
@@ -52,31 +52,65 @@
/*
* HACK for NSS 2.8 to allow Admin to compile without source changes.
*/
#ifndef SEC_BEGIN_PROTOS
#include "seccomon.h"
#endif
+/*
+ * The PORT_*Arena* function signatures mostly involve PLArenaPool* arguments.
+ * But this is misleading! It's not actually safe to use vanilla PLArenaPools
+ * with them. There are two "subclasses" of PLArenaPool that should be used
+ * instead.
+ *
+ * - PORTArenaPool (defined in secport.c): this "subclass" is always
+ * heap-allocated and uses a (heap-allocated) lock to protect all accesses.
+ * Use PORT_NewArena() and PORT_FreeArena() to create and destroy
+ * PORTArenaPools.
+ *
+ * - PORTCheapArenaPool (defined here): this "subclass" can be stack-allocated
+ * and does not use a lock to protect accesses. This makes it cheaper but
+ * less general. It is best used for arena pools that (a) are hot, (b) have
+ * lifetimes bounded within a single function, and (c) don't need locking.
+ * Use PORT_InitArena() and PORT_DestroyArena() to initialize and finalize
+ * PORTCheapArenaPools.
+ *
+ * All the other PORT_Arena* functions will operate safely with either
+ * subclass.
+ */
+typedef struct PORTCheapArenaPool_str {
+ PLArenaPool arena;
+ PRUint32 magic; /* This is used to distinguish the two subclasses. */
+} PORTCheapArenaPool;
+
SEC_BEGIN_PROTOS
extern void *PORT_Alloc(size_t len);
extern void *PORT_Realloc(void *old, size_t len);
extern void *PORT_ZAlloc(size_t len);
extern void PORT_Free(void *ptr);
extern void PORT_ZFree(void *ptr, size_t len);
extern char *PORT_Strdup(const char *s);
extern void PORT_SetError(int value);
extern int PORT_GetError(void);
+/* These functions are for use with PORTArenaPools. */
extern PLArenaPool *PORT_NewArena(unsigned long chunksize);
+extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero);
+
+/* These functions are for use with PORTCheapArenaPools. */
+extern void PORT_InitCheapArena(PORTCheapArenaPool* arena,
+ unsigned long chunksize);
+extern void PORT_DestroyCheapArena(PORTCheapArenaPool* arena);
+
+/* These functions work with both kinds of arena pool. */
extern void *PORT_ArenaAlloc(PLArenaPool *arena, size_t size);
extern void *PORT_ArenaZAlloc(PLArenaPool *arena, size_t size);
-extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero);
extern void *PORT_ArenaGrow(PLArenaPool *arena, void *ptr,
size_t oldsize, size_t newsize);
extern void *PORT_ArenaMark(PLArenaPool *arena);
extern void PORT_ArenaRelease(PLArenaPool *arena, void *mark);
extern void PORT_ArenaZRelease(PLArenaPool *arena, void *mark);
extern void PORT_ArenaUnmark(PLArenaPool *arena, void *mark);
extern char *PORT_ArenaStrdup(PLArenaPool *arena, const char *str);