7181c0af889a0eee451b91ff0b23d67f35e0e772
braney
  Tue Aug 18 08:39:08 2026 -0700
cheapcgi, customTrack, hgSession, hgPhyloPlace: track in-memory uploads in a registry

Uploaded file contents are handed to the reading code as a text address and
size.  Collect that bookkeeping in cheapcgi, which now records each block it
makes and hands back a name for it, and have the custom track, session and
phyloPlace upload paths look the block up by that name.

Also removes the duplicated address/size parsing those callers each had, and
makes lineFileDecompressMem ignore a too-small buffer.

refs #38108

diff --git src/lib/cheapcgi.c src/lib/cheapcgi.c
index cb73dcd9463..2decd97f4de 100644
--- src/lib/cheapcgi.c
+++ src/lib/cheapcgi.c
@@ -231,30 +231,81 @@
 
 
 //============ END of javascript inline-separation routines ===============
 
 
 /* These three variables hold the parsed version of cgi variables. */
 static char *inputString = NULL;
 static unsigned long inputSize;
 static struct hash *inputHash = NULL;
 static struct cgiVar *inputList = NULL;
 
 static boolean haveCookiesHash = FALSE;
 static struct hash *cookieHash = NULL;
 static struct cgiVar *cookieList = NULL;
 
+/* An uploaded file is passed on to the code that reads it as the address and
+ * size of the bytes in memory, written as text into a cgi variable.  Every cgi
+ * variable can also be set by the request, so the address has to be checked
+ * against the blocks we handed out before anything dereferences it.  These
+ * blocks are recorded here, keyed by the same text that names them. */
+static struct hash *memBlobHash = NULL;
+
+struct memBlob
+/* A block of memory named by address in a cgi or cart variable. */
+    {
+    char *mem;			/* Start of the block. */
+    unsigned long size;		/* Size of the block. */
+    };
+
+char *cgiMemBlobRegister(char *mem, unsigned long size)
+/* Record a block of memory that may be named by address in a cgi or cart
+ * variable, and return the "<address> <size>" text that names it.  The
+ * returned string is allocated here and belongs to the caller. */
+{
+char spec[64];
+safef(spec, sizeof(spec), "%lu %lu", (unsigned long)mem, size);
+if (memBlobHash == NULL)
+    memBlobHash = hashNew(4);
+struct memBlob *blob = hashFindVal(memBlobHash, spec);
+if (blob == NULL)
+    {
+    AllocVar(blob);
+    blob->mem = mem;
+    blob->size = size;
+    hashAdd(memBlobHash, spec, blob);
+    }
+return cloneString(spec);
+}
+
+char *cgiMemBlobFind(char *spec, unsigned long *retSize)
+/* Return the block of memory named by spec, which is "<address> <size>" text
+ * made by cgiMemBlobRegister or by an uploaded file part.  Return NULL if this
+ * program never registered such a block, in which case the address came from
+ * the request rather than from us and must not be used.  If retSize is not
+ * NULL the size of the block is returned in it. */
+{
+struct memBlob *blob = NULL;
+if (memBlobHash != NULL && spec != NULL)
+    blob = hashFindVal(memBlobHash, spec);
+if (blob == NULL)
+    return NULL;
+if (retSize != NULL)
+    *retSize = blob->size;
+return blob->mem;
+}
+
 // maximum length of CGI variables to dump to stderr, 0 = switch off
 static int logCgiVarMaxLen = 0;
 
 /* Default cap on total size of CGI input we'll accept, excluding
  * uploaded files.  Used if the GB_CGI_INPUT_SIZE_LIMIT env var
  * (typically supplied via Apache SetEnv) is unset or invalid.
  * See initCgiInput. */
 #define CGI_INPUT_SIZE_LIMIT_DEFAULT (1024*1024)
 
 static long cgiInputSizeLimit()
 /* Return the active CGI input size cap. */
 {
 static long cached = -1;
 if (cached < 0)
     {
@@ -682,37 +733,33 @@
 	safef(varNameFilename, sizeof(varNameFilename), "%s__filename", cdName);
 	AllocVar(el);
 	if (lastPathSep)
 	    el->val = cloneString(lastPathSep+1);
 	else
 	    el->val = cloneString(cdFileName);
         slAddHead(&list, el);
         hashAddSaveName(hash, varNameFilename, el, &el->name);
         }
 
     if (mp->data)
         {
         if (mp->binary)
 	    {
 	    char varNameBinary[256];
-	    char addrSizeBuf[40];
 	    safef(varNameBinary,sizeof(varNameBinary),"%s__binary",cdName);
-            safef(addrSizeBuf,sizeof(addrSizeBuf),"%lu %llu",
-		(unsigned long)mp->data,
-		(unsigned long long)mp->size);
 	    AllocVar(el);
-	    el->val = cloneString(addrSizeBuf);
+	    el->val = cgiMemBlobRegister(mp->data, (unsigned long)mp->size);
 	    slAddHead(&list, el);
 	    hashAddSaveName(hash, varNameBinary, el, &el->name);
 	    }
 	else  /* normal variable, not too big, does not contain zeros */
 	    {
 	    AllocVar(el);
 	    el->val = mp->data;
 	    slAddHead(&list, el);
 	    hashAddSaveName(hash, cdName, el, &el->name);
 	    }
         }
     else if (mp->fileName)
 	{
 	char varNameData[256];
 	safef(varNameData, sizeof(varNameData), "%s__data", cdName);