304e9ab6e3a62d7863b144478fc1ac621623a617
braney
  Wed Jul 29 11:42:01 2026 -0700
Fix data race on the chromAlias caches that was crashing hgTracks in parallel decorator loads.

chromAliasFindNative() and chromAliasFindAliases() lazily created their static
cache hashes and did their first lookup outside the mutex, taking the lock only
for the miss path.  hgTracks loads decorators on real pthreads, so two threads
arriving before a cache existed could race on it and SIGSEGV in hashLookup.
Move the lock above the lazy init and the first lookup so the whole cache
access is inside it.

Both paths of chromAliasFindNative() now return an allocated string rather than
the cache-owned pointer, so document that the caller owns the result, free it in
decorationNativeItem() (called once per decoration), and drop the redundant
outer cloneString() in hgOfficialChromName().

refs #37955

diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c
index 06748ec09d8..726e57f1455 100644
--- src/hg/lib/hdb.c
+++ src/hg/lib/hdb.c
@@ -280,31 +280,31 @@
 
 char *hgOfficialChromName(char *db, char *name)
 /* Returns "canonical" name of chromosome or NULL
  * if not a chromosome. (Case-insensitive search w/sameWord()) */
 {
 if (strlen(name) > HDB_MAX_CHROM_STRING)
     return NULL;
 struct chromInfo *ci = NULL;
 char buf[HDB_MAX_CHROM_STRING];
 strncpy(buf, name, HDB_MAX_CHROM_STRING);
 buf[HDB_MAX_CHROM_STRING-1] = 0;
 ci = hGetChromInfo(db, buf);
 if (ci != NULL)
     return cloneString(ci->chrom);
 
-return cloneString(chromAliasFindNative(name));
+return chromAliasFindNative(name);	// already returns an allocated string
 }	/*	char *hgOfficialChromName(char *db, char *name)	*/
 
 boolean hgIsOfficialChromName(char *db, char *name)
 /* Determine if name is exact (case-sensitive) match with
  * a chromosome in the given assembly */
 {
 char *chrom;
 return ((chrom = hgOfficialChromName(db, name)) != NULL &&
 	sameString(name, chrom));
 }
 
 static boolean minLen = 0;
 
 void setMinIndexLengthForTrashCleaner()
 /* set the minimum index size so trash cleaner will not die