9da759daff220e6433da737debffcc2e81f4de18
chmalee
  Tue Aug 11 09:52:37 2026 -0700
Fixes from code review, refs #38064

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index fca35355391..387b2028ea5 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -4282,47 +4282,52 @@
 
 struct itemColorSpec
 /* A user-chosen color for a single item, set via the right-click "Color this item" menu. */
     {
     Color color;          /* The chosen color. */
     boolean wholeItem;    /* TRUE to recolor the item glyph, FALSE for a background highlight. */
     };
 
 static struct itemColorSpec *itemColorLookup(struct track *tg, void *item)
 /* Return the user-chosen color spec for this item, or NULL. Matches on mapItemName, itemName, or
  * genomic position ("pos:chrom:start-end"), the same identities the JS uses to build the record.
  * Nameless items (e.g. bed3) have no usable name, so the position key identifies them. */
 {
 if (itemColorHash == NULL)
     return NULL;
-char key[2048];
+static struct dyString *key = NULL;
+if (!key)
+    key = dyStringNew(0);
 struct itemColorSpec *spec = NULL;
 if (tg->mapItemName != NULL)
     {
-    safef(key, sizeof key, "%s\t%s", tg->track, tg->mapItemName(tg, item));
-    spec = hashFindVal(itemColorHash, key);
+    dyStringClear(key);
+    dyStringPrintf(key, "%s\t%s", tg->track, tg->mapItemName(tg, item));
+    spec = hashFindVal(itemColorHash, dyStringContents(key));
     }
 if (spec == NULL && tg->itemName != NULL)
     {
-    safef(key, sizeof key, "%s\t%s", tg->track, tg->itemName(tg, item));
-    spec = hashFindVal(itemColorHash, key);
+    dyStringClear(key);
+    dyStringPrintf(key, "%s\t%s", tg->track, tg->itemName(tg, item));
+    spec = hashFindVal(itemColorHash, dyStringContents(key));
     }
 if (spec == NULL && tg->itemStart != NULL && tg->itemEnd != NULL)
     {
-    safef(key, sizeof key, "%s\tpos:%s:%d-%d", tg->track, chromName,
+    dyStringClear(key);
+    dyStringPrintf(key, "%s\tpos:%s:%d-%d", tg->track, chromName,
           tg->itemStart(tg, item), tg->itemEnd(tg, item));
-    spec = hashFindVal(itemColorHash, key);
+    spec = hashFindVal(itemColorHash, dyStringContents(key));
     }
 return spec;
 }
 
 boolean itemColorOverride(struct track *tg, void *item, Color *retColor, boolean *retWholeItem)
 /* If the user set a per-item color for this item (via right-click), return TRUE and fill in the
  * color and whether it recolors the whole item; otherwise return FALSE. Lets non-linkedFeatures
  * draw routines (e.g. bedDrawSimpleAt) honor right-click item colors. */
 {
 struct itemColorSpec *spec = itemColorLookup(tg, item);
 if (spec == NULL)
     return FALSE;
 if (retColor != NULL)
     *retColor = spec->color;
 if (retWholeItem != NULL)
@@ -16349,51 +16354,55 @@
 hgFindMatchesShowHighlight = TRUE;  // default to showing the highlight searched item label.
 }
 
 void createItemColorHash()
 /* Read the itemColors cart variable into a hash of per-item colors keyed by "track\titemName",
  * keeping only records for the current database. The cart format is db#track#mode#itemName#hexColor
  * records joined by '|', where mode is "item" (recolor the glyph) or "bg" (background highlight).
  * The color is the last '#' field so that item names containing '#' are tolerated; item names
  * containing '|' are not supported. The cart value is user-editable, so malformed records (bad
  * color, missing fields) are skipped rather than aborting the image. */
 {
 char *itemColors = cartOptionalString(cart, "itemColors");
 if (isEmpty(itemColors))
     return;
 struct slName *recordList = slNameListFromString(itemColors, '|'), *record;
+struct dyString *colorSpec = dyStringNew(0);
+struct dyString *keyStr = dyStringNew(0);
 for (record = recordList; record != NULL; record = record->next)
     {
     char *p = record->name;
     char *db = cloneNextWordByDelimiter(&p, '#');
     char *track = cloneNextWordByDelimiter(&p, '#');
     char *mode = cloneNextWordByDelimiter(&p, '#');
     char *lastHash = (p != NULL) ? strrchr(p, '#') : NULL;
     if (!isEmpty(db) && !isEmpty(track) && !isEmpty(mode) && lastHash != NULL
             && sameString(db, database))
         {
         *lastHash = '\0';
         char *itemName = p;
         char *hex = lastHash + 1;
-        char colorSpec[16];
-        safef(colorSpec, sizeof colorSpec, "#%s", hex);
+        dyStringPrintf(colorSpec, "#%s", hex);
         unsigned rgb;
-        if (!isEmpty(itemName) && htmlColorForCode(colorSpec, &rgb))
+        if (!isEmpty(itemName) && htmlColorForCode(dyStringContents(colorSpec), &rgb))
             {
             struct itemColorSpec *spec;
             AllocVar(spec);
             spec->color = bedColorToGfxColor(rgb);
             spec->wholeItem = sameString(mode, "item");
-            char key[2048];
-            safef(key, sizeof key, "%s\t%s", track, itemName);
+            dyStringPrintf(keyStr, "%s\t%s", track, itemName);
             if (itemColorHash == NULL)
                 itemColorHash = newHash(0);
-            hashAdd(itemColorHash, key, spec);
+            hashAdd(itemColorHash, dyStringContents(keyStr), spec);
             }
+        dyStringClear(keyStr);
+        dyStringClear(colorSpec);
         }
     freeMem(db);
     freeMem(track);
     freeMem(mode);
     }
+dyStringFree(&keyStr);
+dyStringFree(&colorSpec);
 slFreeList(&recordList);
 }