7b74ff4b43a459efaadb2dc219026d522252745e
braney
  Wed Jun 10 07:09:51 2026 -0700
hgTrackUi: avoid SIGSEGV on duplicate track request not in cart

A request for a dup_-prefixed track name with no matching entry in the
cart passed a NULL dup to dupTdbFrom, causing a null dereference and a
stack dump. This is reachable without a login and was tripped by a bot
during the v499 release. errAbort with a clear message instead.

refs #37743

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index 1256e6428e7..52400e705bd 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -4577,30 +4577,32 @@
     tdb = pcrResultFakeTdb();
 else
     {
     tdb = tdbForTrack(database, track,&tdbList);
     }
 if (tdb == NULL)
    {
    errAbort("Can't find %s in track database %s chromosome %s",
 	    track, database, chromosome);
    }
 
 // Do  little more dupe handling - make a tdb for dupe if any 
 if (isDup)
     {
     struct dupTrack *dup = dupTrackFindInList(dupList, dupWholeName);
+    if (dup == NULL)
+        errAbort("Can't find duplicate track %s", dupWholeName);
     tdb = dupTdbFrom(tdb, dup);
     }
 
 
 if(cartOptionalString(cart, "ajax"))
     {
     // html is going to be used w/n a dialog in hgTracks.js so serve up stripped down html
     // still need CSP2 header for security
     printf("%s", getCspMetaHeader());
     trackUi(tdb, tdbList, ct, TRUE);
     cartRemove(cart,"ajax");
     jsInlineFinish();
     }
 else
     {