From 528032c8476c3cf4f0f9f9272ce63e7d1af4cd43 Mon Sep 17 00:00:00 2001 From: "ian.mcgreer%sun.com" Date: Tue, 5 Feb 2002 23:55:43 +0000 Subject: [PATCH] fixes for bugs 123479 and 123081 (possibly others). break up arena usage in hash table entries for the temp store and cert cache. git-svn-id: svn://10.0.0.236/trunk@113727 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/security/nss/lib/pki/pkistore.c | 16 ++++-- mozilla/security/nss/lib/pki/tdcache.c | 71 +++++++++++++++++++------ 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/mozilla/security/nss/lib/pki/pkistore.c b/mozilla/security/nss/lib/pki/pkistore.c index bd9cbff8161..326bc5dc394 100644 --- a/mozilla/security/nss/lib/pki/pkistore.c +++ b/mozilla/security/nss/lib/pki/pkistore.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: pkistore.c,v $ $Revision: 1.5 $ $Date: 2002-01-31 17:08:32 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: pkistore.c,v $ $Revision: 1.6 $ $Date: 2002-02-05 23:55:42 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef PKIM_H @@ -182,7 +182,7 @@ add_certificate_entry { PRStatus nssrv; certificate_hash_entry *entry; - entry = nss_ZNEW(store->arena, certificate_hash_entry); + entry = nss_ZNEW(cert->object.arena, certificate_hash_entry); if (!entry) { return PR_FAILURE; } @@ -209,7 +209,7 @@ add_subject_entry nssrv = nssList_AddUnique(subjectList, cert); } else { /* Create a new subject list for the subject */ - subjectList = nssList_Create(store->arena, PR_FALSE); + subjectList = nssList_Create(NULL, PR_FALSE); if (!subjectList) { return PR_FAILURE; } @@ -290,9 +290,17 @@ remove_subject_entry if (subjectList) { /* Remove the cert from the subject hash */ nssList_Remove(subjectList, cert); + nssHash_Remove(store->subject, &cert->subject); if (nssList_Count(subjectList) == 0) { - nssHash_Remove(store->subject, &cert->subject); nssList_Destroy(subjectList); + } else { + /* The cert being released may have keyed the subject entry. + * Since there are still subject certs around, get another and + * rekey the entry just in case. + */ + NSSCertificate *subjectCert; + (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1); + nssHash_Add(store->subject, &subjectCert->subject, subjectList); } } } diff --git a/mozilla/security/nss/lib/pki/tdcache.c b/mozilla/security/nss/lib/pki/tdcache.c index ab9fe73ec57..ac4af018b13 100644 --- a/mozilla/security/nss/lib/pki/tdcache.c +++ b/mozilla/security/nss/lib/pki/tdcache.c @@ -32,7 +32,7 @@ */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.23 $ $Date: 2002-01-31 17:08:32 $ $Name: not supported by cvs2svn $"; +static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.24 $ $Date: 2002-02-05 23:55:43 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef PKIM_H @@ -123,18 +123,22 @@ struct cache_entry_str } entry; PRUint32 hits; PRTime lastHit; + NSSArena *arena; }; typedef struct cache_entry_str cache_entry; static cache_entry * -new_cache_entry(NSSArena *arena, void *value) +new_cache_entry(NSSArena *arena, void *value, PRBool ownArena) { cache_entry *ce = nss_ZNEW(arena, cache_entry); if (ce) { ce->entry.value = value; ce->hits = 1; ce->lastHit = PR_Now(); + if (ownArena) { + ce->arena = arena; + } } return ce; } @@ -220,6 +224,13 @@ loser: return PR_FAILURE; } +/* The entries of the hashtable are currently dependent on the certificate(s) + * that produced them. That is, the entries will be freed when the cert is + * released from the cache. If there are certs in the cache at any time, + * including shutdown, the hash table entries will hold memory. In order for + * clean shutdown, it is necessary for there to be no certs in the cache. + */ + NSS_IMPLEMENT PRStatus nssTrustDomain_DestroyCache ( @@ -262,18 +273,21 @@ remove_subject_entry ( nssTDCertificateCache *cache, NSSCertificate *cert, - nssList **subjectList + nssList **subjectList, + NSSArena **arena ) { PRStatus nssrv; cache_entry *ce; *subjectList = NULL; + *arena = NULL; /* Get the subject list for the cert's subject */ ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject); if (ce) { /* Remove the cert from the subject hash */ nssList_Remove(ce->entry.list, cert); *subjectList = ce->entry.list; + *arena = ce->arena; nssrv = PR_SUCCESS; #ifdef DEBUG_CACHE log_cert_ref("removed cert", cert); @@ -333,6 +347,10 @@ remove_email_entry */ (void)nssList_Destroy(subjects); nssHash_Remove(cache->email, cert->email); + /* there are no entries left for this address, free space + * used for email entries + */ + nssArena_Destroy(ce->arena); #ifdef DEBUG_CACHE PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email)); #endif @@ -353,6 +371,7 @@ nssTrustDomain_RemoveCertFromCache nssList *subjectList; PRStatus nssrv; cache_entry *ce; + NSSArena *arena; #ifdef DEBUG_CACHE log_cert_ref("attempt to remove cert", cert); #endif @@ -372,7 +391,7 @@ nssTrustDomain_RemoveCertFromCache if (nssrv != PR_SUCCESS) { goto loser; } - nssrv = remove_subject_entry(td->cache, cert, &subjectList); + nssrv = remove_subject_entry(td->cache, cert, &subjectList, &arena); if (nssrv != PR_SUCCESS) { goto loser; } @@ -388,6 +407,12 @@ nssTrustDomain_RemoveCertFromCache #endif (void)nssList_Destroy(subjectList); nssHash_Remove(td->cache->subject, &cert->subject); + /* there are no entries left for this subject, free the space used + * for both the nickname and subject entries + */ + if (arena) { + nssArena_Destroy(arena); + } } PZ_Unlock(td->cache->lock); NSSCertificate_Destroy(cert); /* release the reference */ @@ -463,7 +488,7 @@ add_issuer_and_serial_entry ) { cache_entry *ce; - ce = new_cache_entry(arena, (void *)cert); + ce = new_cache_entry(arena, (void *)cert, PR_FALSE); #ifdef DEBUG_CACHE log_cert_ref("added to issuer/sn", cert); #endif @@ -499,7 +524,7 @@ add_subject_entry if (!list) { return PR_FAILURE; } - ce = new_cache_entry(arena, (void *)list); + ce = new_cache_entry(arena, (void *)list, PR_TRUE); if (!ce) { return PR_FAILURE; } @@ -546,7 +571,7 @@ add_nickname_entry return PR_FAILURE; } else { NSSUTF8 *nickname; - ce = new_cache_entry(arena, subjectList); + ce = new_cache_entry(arena, subjectList, PR_FALSE); if (!ce) { return PR_FAILURE; } @@ -565,7 +590,6 @@ add_nickname_entry static PRStatus add_email_entry ( - NSSArena *arena, nssTDCertificateCache *cache, NSSCertificate *cert, nssList *subjectList @@ -586,27 +610,37 @@ add_email_entry #endif } else { NSSASCII7 *email; + NSSArena *arena; + arena = nssArena_Create(); + if (!arena) { + return PR_FAILURE; + } /* Create a new list of subject lists, add this subject */ subjects = nssList_Create(arena, PR_TRUE); if (!subjects) { + nssArena_Destroy(arena); return PR_FAILURE; } /* Add the new subject to the list */ nssrv = nssList_AddUnique(subjects, subjectList); if (nssrv != PR_SUCCESS) { + nssArena_Destroy(arena); return nssrv; } /* Add the new entry to the cache */ - ce = new_cache_entry(arena, (void *)subjects); + ce = new_cache_entry(arena, (void *)subjects, PR_TRUE); if (!ce) { + nssArena_Destroy(arena); return PR_FAILURE; } email = nssUTF8_Duplicate(cert->email, arena); if (!email) { + nssArena_Destroy(arena); return PR_FAILURE; } nssrv = nssHash_Add(cache->email, email, ce); if (nssrv != PR_SUCCESS) { + nssArena_Destroy(arena); return nssrv; } #ifdef DEBUG_CACHE @@ -625,11 +659,10 @@ add_cert_to_cache NSSCertificate *cert ) { - NSSArena *arena; + NSSArena *arena = NULL; nssList *subjectList; PRStatus nssrv; PRUint32 added = 0; - arena = td->cache->arena; PZ_Lock(td->cache->lock); /* If it exists in the issuer/serial hash, it's already in all */ if (nssHash_Exists(td->cache->issuerAndSN, cert)) { @@ -643,12 +676,17 @@ add_cert_to_cache nss_SetError(NSS_ERROR_CERTIFICATE_IN_CACHE); return PR_FAILURE; } - /* create a new cache entry for this cert */ - nssrv = add_issuer_and_serial_entry(arena, td->cache, cert); + /* create a new cache entry for this cert within the cert's arena*/ + nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert); if (nssrv != PR_SUCCESS) { goto loser; } added++; + /* create an arena for the nickname and subject entries */ + arena = nssArena_Create(); + if (!arena) { + goto loser; + } /* create a new subject list for this cert, or add to existing */ nssrv = add_subject_entry(arena, td->cache, cert, &subjectList); if (nssrv != PR_SUCCESS) { @@ -667,7 +705,7 @@ add_cert_to_cache added++; } if (cert->email) { - nssrv = add_email_entry(arena, td->cache, cert, subjectList); + nssrv = add_email_entry(td->cache, cert, subjectList); if (nssrv != PR_SUCCESS) { goto loser; } @@ -695,7 +733,7 @@ loser: (void)remove_issuer_and_serial_entry(td->cache, cert); } if (added >= 2) { - (void)remove_subject_entry(td->cache, cert, &subjectList); + (void)remove_subject_entry(td->cache, cert, &subjectList, &arena); } if (added == 3 || added == 5) { (void)remove_nickname_entry(td->cache, cert, subjectList); @@ -703,6 +741,9 @@ loser: if (added >= 4) { (void)remove_email_entry(td->cache, cert, subjectList); } + if (arena) { + nssArena_Destroy(arena); + } PZ_Unlock(td->cache->lock); return PR_FAILURE; }