07ba37612b12dad969ed452c55780c20b7d65712 braney Wed Sep 2 17:03:38 2026 -0700 hgTracks: do not crash when a quickLift chain has no aligned block in the window chainLoadIdRangeHub returns every chain whose span overlaps the window, but only loads the link rows that fall inside it. A chain can therefore reach across the window with no aligned block in it. Its blockList is empty, chainSubsetOnT has nothing to subset, and it returns NULL. bigWigLoadPreDraw dereferenced that NULL and hgTracks died with SIGSEGV, so the user got a blank page. This is what happens on the smaller of the two regions hgConvert offers for a quickLift from hg38 to hs1. Three of the four chains whose span covers hs1 chr7:59,324,765-59,325,193 have no link there. Widen the view past 100 kb and those chains pick up blocks again, which is why only the narrow views crashed. The rest of the quickLift code already skips a chain with an empty blockList. Do the same here. refs #38236 diff --git src/hg/hgTracks/bigWigTrack.c src/hg/hgTracks/bigWigTrack.c index 6a917e76d9c..e4933f116ff 100644 --- src/hg/hgTracks/bigWigTrack.c +++ src/hg/hgTracks/bigWigTrack.c @@ -85,30 +85,38 @@ // FIXME (refs #37621): quickLift bigWig summary issues. // 1. summaryOffset/summarySizeBlock are scaled by retChain->tSize, not // (winEnd - winStart). When a chain only partially covers the visible // window, its blocks get stretched to fill the full preDraw buffer // instead of landing at the correct window pixels. With multiple chains // in chainList, each stretches independently and overwrites the others. // 2. summarySizeBlock is computed from target span but bigWigSummaryArrayExtended // is called with query coordinates; the bigWig zoom level it selects is // based on (qEnd-qStart)/summarySizeBlock, which can pick the wrong zoom // when target and query block lengths differ significantly (indels). for(chain = chainList; chain; chain = chain->next) { struct chain *retChain, *retChainToFree; char *chrom = chain->qName; chainSubsetOnT(chain, winStart, winEnd, &retChain, &retChainToFree); + + // chainLoadIdRangeHub returns every chain whose span overlaps the window, + // but only loads the links that fall inside it. A chain can therefore + // reach across the window with no aligned block in it, in which case + // chainSubsetOnT has nothing to subset and hands back NULL. + if (retChain == NULL) + continue; + struct cBlock *cb; for(cb = retChain->blockList; cb; cb = cb->next) { // figure out where in the summary array the target coordinates put us int tSize = retChain->tEnd - retChain->tStart; int summaryOffset = (((double)cb->tStart - retChain->tStart) / tSize ) * summarySize; int summarySizeBlock = (((double)cb->tEnd - cb->tStart) / tSize ) * summarySize; // grab the data using query coordinates if (summarySizeBlock != 0) { int start = cb->qStart; int end = cb->qEnd; boolean flip = FALSE; if (chain->qStrand == '-')