diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index 3b80648bdee3..ffd8bcd6777b 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -181,6 +181,59 @@ MyPrefChangedCallback(const char*aPrefName, void* instance_data)
}
return 0;
}
+
+// These functions are copied from nsprpub/lib/ds/plhash.c, with one
+// change to free the string used as a key.
+
+static void * PR_CALLBACK
+NamedItemsAllocTable(void *pool, PRSize size)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ return PR_MALLOC(size);
+}
+
+static void PR_CALLBACK
+NamedItemsFreeTable(void *pool, void *item)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ PR_Free(item);
+}
+
+static PLHashEntry * PR_CALLBACK
+NamedItemsAllocEntry(void *pool, const void *key)
+{
+#if defined(XP_MAC)
+#pragma unused (pool,key)
+#endif
+
+ return PR_NEW(PLHashEntry);
+}
+
+static void PR_CALLBACK
+NamedItemsFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ if (flag == HT_FREE_ENTRY) {
+ Recycle((char *)he->key);
+ PR_Free(he);
+ }
+}
+
+static PLHashAllocOps namedItemsHashAllocOps = {
+ NamedItemsAllocTable, NamedItemsFreeTable,
+ NamedItemsAllocEntry, NamedItemsFreeEntry
+};
+
+
// ==================================================================
// =
// ==================================================================
@@ -2778,20 +2831,10 @@ nsHTMLDocument::RouteEvent(nsIDOMEvent* aEvt)
return NS_OK;
}
-PRIntn
-nsHTMLDocument::RemoveStrings(PLHashEntry *he, PRIntn i, void *arg)
-{
- char *str = (char *)he->key;
-
- Recycle(str);
- return HT_ENUMERATE_REMOVE;
-}
-
void
nsHTMLDocument::DeleteNamedItems()
{
if (nsnull != mNamedItems) {
- PL_HashTableEnumerateEntries(mNamedItems, RemoveStrings, nsnull);
PL_HashTableDestroy(mNamedItems);
mNamedItems = nsnull;
}
@@ -2836,7 +2879,6 @@ nsHTMLDocument::UnregisterNamedItems(nsIContent *aContent, PRBool aInForm)
if (IsNamedItem(aContent, tag, aInForm, value)) {
char *nameStr = value.ToNewCString();
- // XXX What about the string held in the hash table entry
PL_HashTableRemove(mNamedItems, nameStr);
Recycle(nameStr);
}
@@ -2864,6 +2906,10 @@ nsHTMLDocument::RegisterNamedItems(nsIContent *aContent, PRBool aInForm)
if (IsNamedItem(aContent, tag, aInForm, value)) {
char *nameStr = value.ToNewCString();
+ // NSPR hashtables will leak keys if given the same entry twice, so
+ // remove first. If it's not in the table, this will fail silently
+ // and quickly (it's one extra lookup).
+ PL_HashTableRemove(mNamedItems, nameStr);
PL_HashTableAdd(mNamedItems, nameStr, aContent);
}
@@ -2942,7 +2988,8 @@ nsHTMLDocument::NamedItem(JSContext* cx, jsval* argv, PRUint32 argc,
// is added and removed.
if (nsnull == mNamedItems) {
mNamedItems = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
- PL_CompareValues, nsnull, nsnull);
+ PL_CompareValues, &namedItemsHashAllocOps,
+ nsnull);
RegisterNamedItems(mRootContent, PR_FALSE);
}
diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h
index 562da66b0a0b..fc70f99571a0 100644
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -190,7 +190,6 @@ protected:
PRBool mShouldMatchCase;
protected:
- static PRIntn PR_CALLBACK RemoveStrings(PLHashEntry *he, PRIntn i, void *arg);
void RegisterNamedItems(nsIContent *aContent, PRBool aInForm);
void UnregisterNamedItems(nsIContent *aContent, PRBool aInForm);
nsIContent* FindNamedItem(nsIContent *aContent, const nsString& aName,
diff --git a/layout/html/document/src/nsHTMLDocument.cpp b/layout/html/document/src/nsHTMLDocument.cpp
index 3b80648bdee3..ffd8bcd6777b 100644
--- a/layout/html/document/src/nsHTMLDocument.cpp
+++ b/layout/html/document/src/nsHTMLDocument.cpp
@@ -181,6 +181,59 @@ MyPrefChangedCallback(const char*aPrefName, void* instance_data)
}
return 0;
}
+
+// These functions are copied from nsprpub/lib/ds/plhash.c, with one
+// change to free the string used as a key.
+
+static void * PR_CALLBACK
+NamedItemsAllocTable(void *pool, PRSize size)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ return PR_MALLOC(size);
+}
+
+static void PR_CALLBACK
+NamedItemsFreeTable(void *pool, void *item)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ PR_Free(item);
+}
+
+static PLHashEntry * PR_CALLBACK
+NamedItemsAllocEntry(void *pool, const void *key)
+{
+#if defined(XP_MAC)
+#pragma unused (pool,key)
+#endif
+
+ return PR_NEW(PLHashEntry);
+}
+
+static void PR_CALLBACK
+NamedItemsFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+#if defined(XP_MAC)
+#pragma unused (pool)
+#endif
+
+ if (flag == HT_FREE_ENTRY) {
+ Recycle((char *)he->key);
+ PR_Free(he);
+ }
+}
+
+static PLHashAllocOps namedItemsHashAllocOps = {
+ NamedItemsAllocTable, NamedItemsFreeTable,
+ NamedItemsAllocEntry, NamedItemsFreeEntry
+};
+
+
// ==================================================================
// =
// ==================================================================
@@ -2778,20 +2831,10 @@ nsHTMLDocument::RouteEvent(nsIDOMEvent* aEvt)
return NS_OK;
}
-PRIntn
-nsHTMLDocument::RemoveStrings(PLHashEntry *he, PRIntn i, void *arg)
-{
- char *str = (char *)he->key;
-
- Recycle(str);
- return HT_ENUMERATE_REMOVE;
-}
-
void
nsHTMLDocument::DeleteNamedItems()
{
if (nsnull != mNamedItems) {
- PL_HashTableEnumerateEntries(mNamedItems, RemoveStrings, nsnull);
PL_HashTableDestroy(mNamedItems);
mNamedItems = nsnull;
}
@@ -2836,7 +2879,6 @@ nsHTMLDocument::UnregisterNamedItems(nsIContent *aContent, PRBool aInForm)
if (IsNamedItem(aContent, tag, aInForm, value)) {
char *nameStr = value.ToNewCString();
- // XXX What about the string held in the hash table entry
PL_HashTableRemove(mNamedItems, nameStr);
Recycle(nameStr);
}
@@ -2864,6 +2906,10 @@ nsHTMLDocument::RegisterNamedItems(nsIContent *aContent, PRBool aInForm)
if (IsNamedItem(aContent, tag, aInForm, value)) {
char *nameStr = value.ToNewCString();
+ // NSPR hashtables will leak keys if given the same entry twice, so
+ // remove first. If it's not in the table, this will fail silently
+ // and quickly (it's one extra lookup).
+ PL_HashTableRemove(mNamedItems, nameStr);
PL_HashTableAdd(mNamedItems, nameStr, aContent);
}
@@ -2942,7 +2988,8 @@ nsHTMLDocument::NamedItem(JSContext* cx, jsval* argv, PRUint32 argc,
// is added and removed.
if (nsnull == mNamedItems) {
mNamedItems = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
- PL_CompareValues, nsnull, nsnull);
+ PL_CompareValues, &namedItemsHashAllocOps,
+ nsnull);
RegisterNamedItems(mRootContent, PR_FALSE);
}
diff --git a/layout/html/document/src/nsHTMLDocument.h b/layout/html/document/src/nsHTMLDocument.h
index 562da66b0a0b..fc70f99571a0 100644
--- a/layout/html/document/src/nsHTMLDocument.h
+++ b/layout/html/document/src/nsHTMLDocument.h
@@ -190,7 +190,6 @@ protected:
PRBool mShouldMatchCase;
protected:
- static PRIntn PR_CALLBACK RemoveStrings(PLHashEntry *he, PRIntn i, void *arg);
void RegisterNamedItems(nsIContent *aContent, PRBool aInForm);
void UnregisterNamedItems(nsIContent *aContent, PRBool aInForm);
nsIContent* FindNamedItem(nsIContent *aContent, const nsString& aName,