758f5d57800f3a5eb3fdd49260bcefbc1435bb91
max
  Mon Oct 5 08:14:28 2026 -0700
cartLoadUserSessionExt: copy the session owner and name before the cart is cleared, so the session-load notice names the loaded session, refs #38472

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 7c33bebee8c..6766c24216c 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -894,30 +894,34 @@
 			 struct hash *oldVars, char *actionVar, boolean merge)
 /* If permitted, load the contents of the given user's session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. 
  * If merge is TRUE, then don't clear the cart first. */
 {
 struct sqlResult *sr = NULL;
 char **row = NULL;
 char *userName = wikiLinkUserName();
 char *encSessionName = cgiEncodeFull(sessionName);
 char *encSessionOwner = cgiEncodeFull(sessionOwner);
 char query[512];
 
+/* The caller may have passed pointers into cart values, which cartRemoveLike below frees. */
+sessionOwner = cloneString(sessionOwner);
+sessionName = cloneString(sessionName);
+
 if (isEmpty(sessionOwner))
     errAbort("Please go back and enter a wiki user name for this session.");
 if (isEmpty(sessionName))
     errAbort("Please go back and enter a session name to load.");
 
 char *queryTempl = "SELECT shared, contents FROM %s WHERE userName = '%s' AND sessionName = '%s';";
 sqlSafef(query, sizeof(query), queryTempl, namedSessionTable, encSessionOwner, encSessionName);
 sr = sqlGetResult(conn, query);
 
 row = sqlNextRow(sr);
 
 // try alternative namedSessionDb tables if no result. Stop on first match.
 struct slName *namedSessionAlts = cfgValsWithPrefix("namedSessionAlt.");
 if (namedSessionAlts && row == NULL)
     {
@@ -986,30 +990,33 @@
         if (cfgOptionBooleanDefault("doMyVariants", FALSE)
             && (userName == NULL || !sameString(sessionOwner, userName)))
             {
             cartRemoveLike(cart, MYVAR_SHARED_CART_PREFIX "*");
             }
         }
     else
 	errAbort("Sharing has not been enabled for user %s's session %s.",
 		 sessionOwner, sessionName);
     }
 else
     errAbort("Could not find session %s for user %s.",
 	     sessionName, sessionOwner);
 sqlFreeResult(&sr);
 freeMem(encSessionName);
+freeMem(encSessionOwner);
+freeMem(sessionOwner);
+freeMem(sessionName);
 }
 
 void cartLoadUserSession(struct sqlConnection *conn, char *sessionOwner,
 			 char *sessionName, struct cart *cart,
 			 struct hash *oldVars, char *actionVar)
 /* If permitted, load the contents of the given user's session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. */
 {
 cartLoadUserSessionExt(conn, sessionOwner,
 			 sessionName, cart,
 			 oldVars, actionVar, FALSE);
 }