Change handling of hash table for OSCP hashes to delete both hash key and

associated value in the hashtable "free entry" routine.  Fixes a memory leak.
(Re Netscape bug: 390117)
This commit is contained in:
thayes%netscape.com 2000-04-06 00:24:43 +00:00
Родитель 9e4a425805
Коммит 1a2f997a52
1 изменённых файлов: 78 добавлений и 30 удалений

Просмотреть файл

@ -34,7 +34,7 @@
/* /*
* Permanent Certificate database handling code * Permanent Certificate database handling code
* *
* $Id: pcertdb.c,v 1.1 2000-03-31 19:42:39 relyea%netscape.com Exp $ * $Id: pcertdb.c,v 1.2 2000-04-06 00:24:43 thayes%netscape.com Exp $
*/ */
#include "prtime.h" #include "prtime.h"
@ -5483,16 +5483,84 @@ typedef struct SPKDigestInfoStr {
#define SPK_DIGEST_TABLE(handle) \ #define SPK_DIGEST_TABLE(handle) \
(((SPKDigestInfo *)(handle->spkDigestInfo))->table) (((SPKDigestInfo *)(handle->spkDigestInfo))->table)
/*
** Hash allocator ops for the SPKDigest hash table. The rules are:
** + The index and value fields are "owned" by the hash table, and are
** freed when the table entry is deleted.
** + Replacing a value in the table is not allowed, since the caller can't
** tell whether the index field was used or not, resulting in a memory
** leak. (This is a bug in the PL_Hash routines.
*/
static void * PR_CALLBACK
spkAllocTable(void *pool, PRSize size)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
return PR_MALLOC(size);
}
static void PR_CALLBACK
spkFreeTable(void *pool, void *item)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
PR_Free(item);
}
/* NOTE: the key argument here appears to be useless, since the RawAdd
* routine in PL_Hash just uses the original anyway.
*/
static PLHashEntry * PR_CALLBACK
spkAllocEntry(void *pool, const void *key)
{
#if defined(XP_MAC)
#pragma unused (pool,key)
#endif
return PR_NEW(PLHashEntry);
}
static void PR_CALLBACK
spkFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
SECItem *value = (SECItem *)he->value;
/* The flag should always be to free the whole entry. Otherwise the
* index field gets leaked because the caller can't tell whether
* the "new" value (which is the same as the old) was used or not.
*/
PORT_Assert(flag == HT_FREE_ENTRY);
/* We always free the value */
SECITEM_FreeItem(value, PR_TRUE);
if (flag == HT_FREE_ENTRY)
{
/* Comes from BTOA, is this the right free call? */
PORT_Free((char *)he->key);
PR_Free(he);
}
}
static PLHashAllocOps spkHashAllocOps = {
spkAllocTable, spkFreeTable,
spkAllocEntry, spkFreeEntry
};
/* /*
* Create the key hash lookup table. Note that the table, and the * Create the key hash lookup table. Note that the table, and the
* structure which holds it and a little more information, is never freed. * structure which holds it and a little more information, is never freed.
* This is because the temporary database is never actually closed out, * This is because the temporary database is never actually closed out,
* so there is no safe/obvious place to free the whole thing. Also, * so there is no safe/obvious place to free the whole thing.
* every time an entry is added to the table, the key under which it is
* added is leaked. I think the only way to fix that is to provide our
* own allocation functions to PL_NewHashTable. But I'm not in the mood
* to do that, given that all of this is about to change, and we should
* have the key hash lookup done inside the permanent database itself.
* *
* The database must be locked already. * The database must be locked already.
*/ */
@ -5512,7 +5580,7 @@ InitDBspkDigestInfo(CERTCertDBHandle *handle)
table = PL_NewHashTable(128, PL_HashString, PL_CompareStrings, table = PL_NewHashTable(128, PL_HashString, PL_CompareStrings,
(PLHashComparator) SECITEM_ItemsAreEqual, (PLHashComparator) SECITEM_ItemsAreEqual,
NULL, NULL); &spkHashAllocOps, NULL);
if ( table == NULL ) { if ( table == NULL ) {
PORT_Free(spkDigestInfo); PORT_Free(spkDigestInfo);
return(SECFailure); return(SECFailure);
@ -5662,7 +5730,6 @@ RemoveCertFromSPKDigestTableForAlg(CERTCertDBHandle *handle,
CERTCertificate *cert, SECOidTag digestAlg) CERTCertificate *cert, SECOidTag digestAlg)
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
SECItem *certDBKey = NULL;
char *index = NULL; char *index = NULL;
PLHashTable *table; PLHashTable *table;
@ -5678,25 +5745,11 @@ RemoveCertFromSPKDigestTableForAlg(CERTCertDBHandle *handle,
goto done; goto done;
} }
/*
* Get hold of this value so we can free it after doing the remove.
*/
certDBKey = PL_HashTableLookup(table, index);
if ( certDBKey == NULL ) {
/* not found means nothing to remove, which is fine */
goto done;
}
if ( PL_HashTableRemove(table, index) != PR_TRUE ) { if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
/* This should not actually happen, since we already did a lookup. */ /* not found means nothing to remove, which is fine */
PORT_Assert(0);
rv = SECFailure;
} }
done: done:
if ( certDBKey != NULL ) {
SECITEM_FreeItem(certDBKey, PR_TRUE);
}
if ( index != NULL ) { if ( index != NULL ) {
PORT_Free(index); PORT_Free(index);
} }
@ -5743,7 +5796,7 @@ AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
SECItem *certDBKey, SECOidTag digestAlg) SECItem *certDBKey, SECOidTag digestAlg)
{ {
SECStatus rv = SECFailure; SECStatus rv = SECFailure;
SECItem *oldCertDBKey = NULL; SECItem *oldCertDBKey;
PRBool addit = PR_TRUE; PRBool addit = PR_TRUE;
CERTCertificate *oldCert = NULL; CERTCertificate *oldCert = NULL;
char *index = NULL; char *index = NULL;
@ -5785,7 +5838,6 @@ AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
if ( cert == oldCert ) { if ( cert == oldCert ) {
/* They are the same cert, so we are done. */ /* They are the same cert, so we are done. */
addit = PR_FALSE; addit = PR_FALSE;
oldCertDBKey = NULL; /* don't want to free it */
} else if ( CERT_IsNewer(cert, oldCert) ) { } else if ( CERT_IsNewer(cert, oldCert) ) {
if ( PL_HashTableRemove(table, index) != PR_TRUE ) { if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
goto loser; goto loser;
@ -5793,7 +5845,6 @@ AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
} else { } else {
/* oldCert is "newer", so we are done. */ /* oldCert is "newer", so we are done. */
addit = PR_FALSE; addit = PR_FALSE;
oldCertDBKey = NULL; /* don't want to free it */
} }
} }
} }
@ -5814,9 +5865,6 @@ AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
rv = SECSuccess; rv = SECSuccess;
loser: loser:
if ( oldCertDBKey != NULL ) {
SECITEM_FreeItem(oldCertDBKey, PR_TRUE);
}
if ( index != NULL ) { if ( index != NULL ) {
PORT_Free(index); PORT_Free(index);
} }