01fbc2b46b7fe918aa6628cca8ca8ee7ede0e598
braney
  Wed Aug 19 17:54:38 2026 -0700
pgSnp: replace a fixed-size local array in alleleCountsFromVcfRecord with an allocation sized from the record, refs #38154

diff --git src/hg/lib/pgSnp.c src/hg/lib/pgSnp.c
index c383e196419..950bde5f750 100644
--- src/hg/lib/pgSnp.c
+++ src/hg/lib/pgSnp.c
@@ -722,49 +722,51 @@
                   row[3], item->alleleCount);
 /* read count, comma separated list of numbers with above # of items */
 item->alleleFreq = cloneString(row[5]);
 char pattern[128];
 safef(pattern, sizeof(pattern), "^[0-9]+(,[0-9]+){%d}$", item->alleleCount - 1);
 if (! regexMatchNoCase(row[5], pattern))
     lineFileAbort(lf, "invalid allele frequency, %s with count of %d", row[5], item->alleleCount);
 /* scores, comma separated list of numbers with above # of items */
 item->alleleScores = cloneString(row[6]);
 safef(pattern, sizeof(pattern), "^[0-9.]+(,[0-9.]+){%d}$", item->alleleCount - 1);
 if (! regexMatchNoCase(row[6], pattern))
     lineFileAbort(lf, "invalid allele scores, %s with count of %d", row[6], item->alleleCount);
 return item;
 }
 
-#define VCF_MAX_ALLELE_LEN 80
-
 static char *alleleCountsFromVcfTumorAd(const struct vcfInfoElement *ad)
 /* Build up comma-sep list of read counts supporting tumor alleles */
 {
 struct dyString *dy = dyStringNew(0);
 // Assume only one alternate allele
 int r = ad->values[0].datInt;
 int a = ad->values[1].datInt;
 dyStringPrintf(dy, "%d,%d", r, a);
 return dyStringCannibalize(&dy);
 }
 
 static char *alleleCountsFromVcfRecord(struct vcfRecord *rec, int alDescCount)
 /* Build up comma-sep list of per-allele counts, if available, up to alDescCount
  * which may be less than rec->alleleCount: */
 {
 struct dyString *dy = dyStringNew(0);
-int alCounts[VCF_MAX_ALLELE_LEN];
+// Repeat sites can have hundreds of alleles, so size this by the record instead of
+// using a fixed-size array.
+int alCountSize = max(alDescCount, rec->alleleCount) + 1;
+int *alCounts = NULL;
+AllocArray(alCounts, alCountSize);
 boolean gotTotalCount = FALSE, gotAltCounts = FALSE;
 int i;
 for (i = 0;  i < rec->infoCount;  i++)
     if (sameString(rec->infoElements[i].key, "AN"))
 	{
 	if (rec->infoElements[i].missingData[0])
 	    break;
 	gotTotalCount = TRUE;
 	// Set ref allele to total count, subtract alt counts below.
 	alCounts[0] = rec->infoElements[i].values[0].datInt;
 	break;
 	}
 for (i = 0;  i < rec->infoCount;  i++)
     if (sameString(rec->infoElements[i].key, "AC"))
 	{
@@ -846,30 +848,31 @@
 	alCounts[i] = 0;
     for (i = 0;  i < rec->file->genotypeCount;  i++)
 	{
 	struct vcfGenotype *gt = &(rec->genotypes[i]);
 	if (gt == NULL)
 	    uglyf("i=%d gt=NULL wtf?\n", i);
 	if (gt->hapIxA >= 0)
 	    alCounts[(unsigned char)gt->hapIxA]++;
 	if (!gt->isHaploid && gt->hapIxB >= 0)
 	    alCounts[(unsigned char)gt->hapIxB]++;
 	}
     dyStringPrintf(dy, "%d", alCounts[0]);
     for (i = 1;  i < alDescCount;  i++)
 	dyStringPrintf(dy, ",%d", alCounts[i]);
     }
+freeMem(alCounts);
 return dyStringCannibalize(&dy);
 }
 
 static void pgSnpFromVcfSgtIndelRecord(struct vcfRecord *rec, struct pgSnp *pgs)
 /* parse alleles and frequency from vcf file with SGT for indels */
 {
 pgs->alleleCount = 2; // assume always 2: normal->tumor
 struct dyString *dy = dyStringCreate("%s/%s", rec->alleles[0], rec->alleles[1]);
 pgs->name = dyStringCannibalize(&dy);
 int refCnt = -1, altCnt = -1;
 const struct vcfGenotype *gt = vcfRecordFindGenotype(rec, "TUMOR");
 if (gt)
     {
     const struct vcfInfoElement *dp = vcfGenotypeFindInfo(gt, "DP");
     const struct vcfInfoElement *tar = vcfGenotypeFindInfo(gt, "TAR");