3e29ad0059ebf3c9b781ac5317e692ae2a2687bb
braney
  Tue Jan 14 23:31:45 2020 -0800
hgCollection fiddles with the settingsHash of trackDb, which might be
cached and made up of memory that shouldn't be freed.   Copy the hash
before fiddling with it.   Found a bug in lmCloneHash (wasn't setting
hash->lm correctly, so increment trackDb version just to make sure cache
will be cleared.

diff --git src/lib/localmem.c src/lib/localmem.c
index 7030a53..4d8b0d9 100644
--- src/lib/localmem.c
+++ src/lib/localmem.c
@@ -1,26 +1,27 @@
 /* LocalMem.c - local memory routines. 
  * 
  * These routines are meant for the sort of scenario where
  * a lot of little to medium size pieces of memory are
  * allocated, and then disposed of all at once.
  *
  * This file is copyright 2002 Jim Kent, but license is hereby
  * granted for all use - public, private or commercial. */
 
 
 #include "common.h"
+#include "hash.h"
 #include "localmem.h"
 
 
 struct lm
     {
     struct lmBlock *blocks;
     size_t blockSize;
     size_t allignMask;
     size_t allignAdd;
     boolean doMemoryAllocs; // if true, do our own memory allocs, otherwise use passed in pointer
     };
 
 struct lmBlock
     {
     struct lmBlock *next;
@@ -279,15 +280,51 @@
 ref->val = val;
 slAddHead(pRefList, ref);
 }
 
 char *lmJoinStrings(struct lm *lm, char *a, char *b)
 /* Return concatenation of a and b allocated in lm */
 {
 int aSize = strlen(a);
 int resSize = aSize + strlen(b) + 1;
 char *output = lmAlloc(lm, resSize);
 strcpy(output, a);
 strcpy(output + aSize, b);
 return output;
 }
 
+static struct hashEl *lmCloneHashElList(struct lm *lm, struct hashEl *list)
+/* Clone a list of hashEl's. */
+{
+struct hashEl *newList = NULL;
+
+for(; list; list = list->next)
+    {
+    struct hashEl *hel = lmAlloc(lm, sizeof(struct hashEl));
+    slAddHead(&newList, hel);
+    hel->name = lmCloneString(lm, list->name);
+    hel->val = lmCloneString(lm, (char *)list->val);  // we're assuming that the values are strings
+    hel->hashVal = list->hashVal;
+    }
+
+return newList;
+}
+
+struct hash *lmCloneHash(struct lm *lm, struct hash *hash)
+/* Clone a hash into local memory. ASSUMES VALUES ARE STRINGS */
+{
+struct hash *newHash = lmAlloc(lm, sizeof(struct hash));
+
+*newHash = *hash;
+newHash->lm = lm;
+newHash->ownLm = TRUE;
+newHash->next = NULL;
+lmAllocArray(lm, newHash->table, hash->size);
+
+int ii;
+for(ii=0; ii < hash->size; ii++)
+    if (hash->table[ii] != NULL)
+        newHash->table[ii] = lmCloneHashElList(lm, hash->table[ii]);
+
+return newHash;
+}
+