8e33b480ded84760b7c96de88ab953102fbff466
braney
  Fri Mar 15 10:56:11 2024 -0700
replace code that was potentially allocating too much memory off the
stack with memory allocated off the heap and never freed.

diff --git src/lib/basicBed.c src/lib/basicBed.c
index 3899ebb..3251f15 100644
--- src/lib/basicBed.c
+++ src/lib/basicBed.c
@@ -1424,30 +1424,49 @@
 boolean result = FALSE;
 struct asObject *asStandard = NULL;
 if (numColumnsToCheck > 15)
     errAbort("There are only 15 standard BED columns defined and you have asked for %d.", numColumnsToCheck);
 if (numColumnsToCheck < 3)
     errAbort("All BED files must have at least 3 columns. (Is it possible that you provided a chrom.sizes file instead of a BED file?)");
 char *asStandardText = bedAsDef(15,15);
 asStandard = asParseText(asStandardText);
 result = asCompareObjs("Yours", asYours, "BED Standard", asStandard, numColumnsToCheck, NULL, abortOnDifference);
 freeMem(asStandardText);
 asObjectFreeList(&asStandard);
 return result;
 }
 
 
+static char *getScratchMem(unsigned size)
+// allocate some temporary memory that will never be freed except
+// if it's not big enough.
+{
+static unsigned currentSize = 0;
+static char *currentMem = NULL;
+
+if (size > currentSize)
+    {
+    if (currentMem)
+        freeMem(currentMem);
+
+    currentSize = size;
+    currentMem = needLargeMem(size);
+    }
+
+return currentMem;
+}
+
 void loadAndValidateBedExt(char *row[], int bedFieldCount, int fieldCount, struct lineFile *lf, struct bed * bed, struct asObject *as, boolean isCt,  boolean allow1bpOverlap)
 /* Convert a row of strings to a bed and validate the contents.  Abort with message if invalid data. Optionally validate bedPlus via asObject.
  * If a customTrack, then some errors are tolerated. Possibly allow exons to overlap by one base. */
 {
 int count;
 int *blockSizes = NULL;
 int *chromStarts;
 
 bed->chrom = row[0];  // note this value is not cloned for speed, callers may need to clone it.
 
 // This check is usually redundant since the caller should be checking it against actual chromInfo names
 // however hgLoadBed might not always have that info available.
 if (strlen(bed->chrom) >= BB_MAX_CHROM_STRING)  // must leave room for 0 terminator
     lineFileAbort(lf, "chrom [%s] is too long (must not exceed %d characters)", bed->chrom, BB_MAX_CHROM_STRING - 1);
 if (strlen(bed->chrom) < 1)
@@ -1533,34 +1552,40 @@
 	}
     else 
 	{
 	lineFileAllInts(lf, row, 8, &bed->itemRgb, FALSE, 4, "integer", FALSE);
 	}
     }
 
 int tempArraySize = 1;	// How big arrays are below
 if (bedFieldCount > 9)
     {
     lineFileAllInts(lf, row, 9, &bed->blockCount, FALSE, 4, "integer", FALSE);
     if (!(bed->blockCount >= 1))
 	lineFileAbort(lf, "Expecting blockCount (%d) to be 1 or more.", bed->blockCount);
     tempArraySize = bed->blockCount;
     }
-int tempBlockSizes[tempArraySize];
-int tempChromStarts[tempArraySize];
-int tempExpIds[tempArraySize];
-float tempExpScores[tempArraySize];
+
+// this memory never gets freed, but tempArraySize can be huge so
+// we can't allocate it off the stack and we don't want to be 
+// allocating and freeing it millions of times on huge beds.
+char *allocatedMem = getScratchMem(3 * tempArraySize * sizeof(int) + tempArraySize * sizeof(float));
+int *tempBlockSizes = (int *)allocatedMem;
+int *tempChromStarts = (int *)&allocatedMem[tempArraySize * sizeof(int)];
+int *tempExpIds = (int *)&allocatedMem[2*tempArraySize * sizeof(int)];
+float *tempExpScores = (float *)&allocatedMem[3*tempArraySize * sizeof(int)];
+
 if (bedFieldCount > 10)
     {
     if (isCt)
 	{
 	AllocArray(bed->blockSizes,bed->blockCount+1); // having +1 allows us to detect incorrect size
         count = lineFileAllIntsArray(lf, row, 10, bed->blockSizes, bed->blockCount+1, TRUE, 4, "integer", TRUE);
 	blockSizes = bed->blockSizes;
 	}
     else
 	{
         count = lineFileAllIntsArray(lf, row, 10, tempBlockSizes, tempArraySize, TRUE, 4, "integer", TRUE);
 	blockSizes = tempBlockSizes;
 	}
     if (count != bed->blockCount)
 	lineFileAbort(lf, "Expecting %d elements in blockSizes list, found at least %d", bed->blockCount, count);