5f590f874b9d352023167b563e5b83f651488f0b
max
  Tue Sep 15 04:56:35 2026 -0700
Resolve $hgsid in native track description pages too, refs #38283

A description page could already use $hgsid if it belonged to a hub, because a hub's
html is substituted at render time where there is a cart. A native page is substituted
once by hgTrackDb, which has no cart, so $hgsid quietly became the empty string and the
link it was part of came out broken. hg38's hprcRdt page has been shipping
"hgTrackUi?hgsid=&g=long_read_transcripts" for this reason.

hgTrackDb now writes the reference back out as ${hgsid} instead of resolving it, and
hVarSubstTrackDbHtml resolves it at render time for native pages as well as hub ones.
Only $hgsid is deferred, and only in the html field: the labels get no second pass, so a
deferred reference in one of them would reach the user as the literal text "${hgsid}".
The render pass over a native page acts only on the braced form, which is what keeps an
escaped $$hgsid escaped -- hgTrackDb collapses that to a bare $hgsid, and a bare one is
left alone.

The html is no longer freed before being replaced, and is replaced only when the
substitution actually changed something. hVarSubstExt allocates its result at the first
dollar sign whether or not it substitutes anything, so any page merely containing one
reached that free; for a native track tdb->html can point into the trackDb cache, which
is localmem carved out of an mmap'd file and never came from malloc. Reproduced on hg38
chm13LiftOver, whose page contains an awk snippet, with cacheTrackDbDir set.

Description pages have to be reloaded for the deferral to reach the trackDb table.

diff --git src/hg/inc/hVarSubst.h src/hg/inc/hVarSubst.h
index d657292f331..adf8ab793c5 100644
--- src/hg/inc/hVarSubst.h
+++ src/hg/inc/hVarSubst.h
@@ -1,42 +1,42 @@
 /** Handle variable substitutions in strings from trackDb and other
  * labels. See trackDb/README for descriptions of values that 
  * can be substitute. */
 
 /* Copyright (C) 2009 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 #ifndef hVarSubst_h
 #define hVarSubst_h
 
 #include "trackDb.h"
 #include "cart.h"
 
 
 char *hVarSubst(char *desc, struct trackDb *tdb, char *database, char *src);
 /* Parse a string and substitute variable references.  Return NULL if
  * no variable references were found.  Error on missing variables (except
  * $matrix).  desc is a brief description to print on error to help with
  * debugging. tdb maybe NULL to only do substitutions based on database
  * and organism. See trackDb/README for more information.*/
 
 void hVarSubstInVar(char *desc, struct trackDb *tdb, char *database, char **varPtr);
 /* hVarSubst on a dynamically allocated string, replacing string in substitutions
  * occur, freeing the old memory if necessary.  See hVarSubst for details.
  */
 
 void hVarSubstWithCart(char *desc, struct cart *cart, struct trackDb *tdb, char *database,
                        char **varPtr);
 /* Like hVarSubstInVar, but if cart is non-NULL, $hgsid will be substituted. */
 
 void hVarSubstTrackDb(struct trackDb *tdb, char *database);
 /* Substitute variables in trackDb shortLabel, longLabel, and html fields. */
 
 void hVarSubstTrackDbHtml(struct cart *cart, struct trackDb *tdb, char *database);
-/* Substitute variables in the description page of a hub track.  Native trackDb needs no
- * such call: hgTrackDb already substituted the html when it loaded trackDb.  A hub's html
- * comes straight off the hub's web server and has never been through substitution, so it
- * is done here, at render time, where $db, $hgsid and $parentTrack resolve to the hub_<id>_
- * names the CGIs actually use.  Only a short list of variables is recognized and nothing
- * is an error, so a dollar sign in a description page that was not written with this in
- * mind stays a dollar sign. */
+/* Substitute variables in a track's description page, at render time, where there is a
+ * cart and where $db, $hgsid and $parentTrack resolve to the hub_<id>_ names the CGIs
+ * actually use.  A hub's html has never been through substitution, so a short list of
+ * variables is resolved here.  A native page was already done by hgTrackDb, apart from
+ * $hgsid, which cannot be baked into the trackDb table because it is per-request.
+ * Nothing is an error, so a dollar sign in a description page that was not written with
+ * this in mind stays a dollar sign. */
 
 #endif