38bab7f62d250db395c83bd4b6b0d6c08799ef59 markd Sat Aug 15 20:01:54 2026 -0700 Make maf UI species arrays dynamic to fix crash on large mafs. refs #38039 The Codon Translation dropdown in wigMafCfgUi built its option list in a fixed nodeNames[512] stack array, so a maf with more than 511 species wrote past the end of the frame and crashed hgTrackUi. Size it from slCount of the species list instead. Three more fixed arrays in the same path silently dropped data rather than crashing: wigMafGetSpecies chopped speciesOrder into species[2000] and speciesGroups into a 1000 entry array, and wigMafSpeciesTable chopped speciesDefaultOff into words[2000]. All now count with chopLineLen and allocate. Verified by driving wigMafCfgUi directly: 700 species segfaulted before and renders now, and 3000 species previously lost everything past 2000. hgTrackUi output for hg38 multiz470way is unchanged. diff --git src/hg/lib/hui.c src/hg/lib/hui.c index 03f819249e5..19e5c9a0ddb 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -1,10835 +1,10844 @@ /* hui - human genome user interface common controls. */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "jksql.h" #include "jsHelper.h" #include "sqlNum.h" #include "cart.h" #include "hdb.h" #include "hui.h" #include "hCommon.h" #include "hgConfig.h" #include "chainCart.h" #include "chainDb.h" #include "netCart.h" #include "obscure.h" #include "wiggle.h" #include "phyloTree.h" #include "hgMaf.h" #include "udc.h" #include "customTrack.h" #include "encode/encodePeak.h" #include "mdb.h" #include "web.h" #include "hPrint.h" #include "fileUi.h" #include "bigBed.h" #include "bigRmskUi.h" #include "bigWig.h" #include "regexHelper.h" #include "snakeUi.h" #include "vcfUi.h" #include "vcf.h" #include "errCatch.h" #include "samAlignment.h" #include "myVariants.h" #include "bedDetail.h" #include "pgSnp.h" #include "memgfx.h" #include "trackHub.h" #include "genark.h" #include "gtexUi.h" #include "genbank.h" #include "htmlPage.h" #include "longRange.h" #include "barChartUi.h" #include "interactUi.h" #include "interact.h" #include "hicUi.h" #include "bigDbSnp.h" #include "customComposite.h" #include "trackVersion.h" #include "hubConnect.h" #include "bigBedFilter.h" #include "bedMethyl.h" // TODO: these should go away after refactoring of multi-region link #include "hex.h" #include "net.h" #include "trashDir.h" #include #define SMALLBUF 256 #define MAX_SUBGROUP 9 #define ADD_BUTTON_LABEL "Show All" #define CLEAR_BUTTON_LABEL "Hide All" #define JBUFSIZE 2048 #define DEF_BUTTON "\"%s\"\n" #define DEF_BUTTON_JS "setCheckBoxesThatContain('%s',true,false,'%s','','%s');" \ "setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');" #define DEFAULT_BUTTON(nameOrId,anc,beg,contains) \ printf(DEF_BUTTON,(anc),"defaults_sm.png","default"); \ safef(id, sizeof id, "btn_%s", (anc)); \ jsOnEventByIdF("click", id, DEF_BUTTON_JS,(nameOrId),(beg),(contains),(nameOrId),(beg),(contains)); #define PM_BUTTON "\"%s\"\n" #define PM_BUTTON_JS "setCheckBoxesThatContain('%s',%s,true,'%s','','%s');" #define PLUS_BUTTON(nameOrId,anc,beg,contains) \ printf(PM_BUTTON, (anc), "add_sm.gif", "+"); \ safef(id, sizeof id, "btn_%s", (anc)); \ jsOnEventByIdF("click", id, PM_BUTTON_JS, (nameOrId),"true", (beg),(contains)); #define MINUS_BUTTON(nameOrId,anc,beg,contains) \ printf(PM_BUTTON, (anc), "remove_sm.gif", "-"); \ safef(id, sizeof id, "btn_%s", (anc)); \ jsOnEventByIdF("click", id, PM_BUTTON_JS, (nameOrId),"false", (beg),(contains)); boolean isEncode2(char *database, char *track) /* Return true for tracks created by UCSC DCC during ENCODE production phase */ { if (startsWith("wgEncode", track)) return (sameString(database, "hg18") || sameString(database, "hg19") || sameString(database, "mm9")); return FALSE; } static char *htmlStringForDownloadsLink(char *database, struct trackDb *tdb, char *name,boolean nameIsFile) // Returns an HTML string for a downloads link { // If has fileSortOrder, then link to new hgFileUi if (!nameIsFile && trackDbSetting(tdb, FILE_SORT_ORDER) != NULL) { char * link = needMem(PATH_LEN); // 512 should be enough safef(link,PATH_LEN,"%s", hgFileUiName(),database, /*cartSessionVarName(),cartSessionId(cart),*/ tdb->track, name); // Note the hgsid would be needed if downloads page ever saved fileSortOrder to cart. return link; } else if (trackDbSetting(tdb, "wgEncode") != NULL && isEncode2(database, tdb->track)) // Downloads directory if this is ENCODE { const char *compositeDir = metadataFindValue(tdb, MDB_OBJ_TYPE_COMPOSITE); if (compositeDir == NULL && tdbIsComposite(tdb)) compositeDir = tdb->track; if (compositeDir != NULL) { struct dyString *dyLink = dyStringCreate("%s", hDownloadsServer(), database, ENCODE_DCC_DOWNLOADS, compositeDir, (nameIsFile?name:""), nameIsFile?"file":"files",name); return dyStringCannibalize(&dyLink); } } return NULL; } static boolean makeNamedDownloadsLink(char *database, struct trackDb *tdb,char *name) // Make a downloads link (if appropriate and then returns TRUE) { char *htmlString = htmlStringForDownloadsLink(database,trackDbTopLevelSelfOrParent(tdb),name,FALSE); if (htmlString == NULL) return FALSE; printf("%s", htmlString); freeMem(htmlString); return TRUE; } boolean makeDownloadsLink(char *database, struct trackDb *tdb) // Make a downloads link (if appropriate and then returns TRUE) { return makeNamedDownloadsLink(database, tdb,"Downloads"); } void makeTopLink(struct trackDb *tdb) // Link to top of UI page { if (trackDbSetting(tdb, "dimensions")) { char *upArrow = "⇑"; enum browserType browser = cgiBrowser(); if (browser == btIE || browser == btFF) upArrow = "↑"; // Note: the nested spans are so that javascript can determine position // and selectively display the link when appropriate printf("",upArrow); } } boolean makeSchemaLink(char *db,struct trackDb *tdb,char *label) // Make a table schema link (if appropriate and then returns TRUE) { #define SCHEMA_LINKED "%s" if (trackDataAccessible(db, tdb) && differentString("longTabix", tdb->type)) // FIXME: hgTables.showSchmaLongTabix is a currently a dummy routine, so let's not got here // until it's implemented { char *tbOff = trackDbSetting(tdb, "tableBrowser"); if (isNotEmpty(tbOff) && sameString(nextWord(&tbOff), "off")) { puts("(Download unavailable, see below)"); return FALSE; } char *hint = " title='Open data format (table schema) in new window'"; if (label == NULL) label = " View data format"; struct trackDb *topLevel = trackDbTopLevelSelfOrParent(tdb); printf(SCHEMA_LINKED, db, topLevel->grp, topLevel->track, tdb->table, hint, label); return TRUE; } return FALSE; } char *wgEncodeVocabLink(char *term,char *value,char *title, char *label,char *suffix) // returns allocated string of HTML link to controlled vocabulary term { #define VOCAB_LINK "%s" struct dyString *dyLink = NULL; char *encTerm = cgiEncode(term); char *encValue = cgiEncode(value); dyLink = dyStringCreate(VOCAB_LINK,encTerm,encValue,title,label); if (suffix != NULL) dyStringAppend(dyLink,suffix); // Don't encode since this may contain HTML freeMem(encTerm); freeMem(encValue); return dyStringCannibalize(&dyLink); } char *pairsAsHtmlTable( struct slPair *pairs, struct trackDb *tdb, boolean showLongLabel,boolean showShortLabel) /* Return a string which is an HTML table of the tags for this track. */ { if (pairs == NULL) return ""; struct dyString *dyTable = dyStringCreate(""); if (showLongLabel) dyStringPrintf(dyTable,"",tdb->longLabel); if (showShortLabel) dyStringPrintf(dyTable,"" "",tdb->shortLabel); for(; pairs; pairs = pairs->next) { if (!sameString(pairs->name, "meta") && !isEmpty((char *)pairs->val)) dyStringPrintf(dyTable,"" "",pairs->name, (char *)pairs->val); } dyStringAppend(dyTable,"
%s
shortLabel:%s
%s:%s
"); return dyStringCannibalize(&dyTable); } char *metadataAsHtmlTable(char *db,struct trackDb *tdb,boolean showLongLabel,boolean showShortLabel) // If metadata from metaDb exists, return string of html with table definition { struct slPair *pairs = NULL; if ((pairs = trackDbMetaPairs(tdb)) != NULL) return pairsAsHtmlTable(pairs, tdb, showLongLabel, showShortLabel); const struct mdbObj *safeObj = metadataForTable(db,tdb,NULL); if (safeObj == NULL || safeObj->vars == NULL) return NULL; //struct dyString *dyTable = dyStringCreate("",tdb->table); struct dyString *dyTable = dyStringCreate("
"); if (showLongLabel) dyStringPrintf(dyTable,"",tdb->longLabel); if (showShortLabel) dyStringPrintf(dyTable,"" "",tdb->shortLabel); // Get the hash of mdb and cv term types struct hash *cvTermTypes = (struct hash *)cvTermTypeHash(); struct mdbObj *mdbObj = mdbObjClone(safeObj); // Important if we are going to remove vars! // Don't bother showing these mdbObjRemoveVars(mdbObj,MDB_OBJ_TYPE_COMPOSITE " " MDB_VAR_PROJECT " " MDB_OBJ_TYPE " " MDB_VAR_MD5SUM); mdbObjRemoveHiddenVars(mdbObj); mdbObjReorderByCv(mdbObj,FALSE);// Use cv defined order for visible vars struct mdbVar *mdbVar; for (mdbVar=mdbObj->vars;mdbVar!=NULL;mdbVar=mdbVar->next) { if ((sameString(mdbVar->var,MDB_VAR_FILENAME) || sameString(mdbVar->var,MDB_VAR_FILEINDEX) ) && trackDbSettingClosestToHome(tdb,MDB_VAL_ENCODE_PROJECT) != NULL) { dyStringPrintf(dyTable,"" ""); } else { // Don't bother with tableName if (cvTermTypes && differentString(mdbVar->var,MDB_VAR_TABLENAME)) { struct hash *cvTerm = hashFindVal(cvTermTypes,mdbVar->var); if (cvTerm != NULL) // even if cvTerm isn't used, { // it proves that it exists and a link is desirable if (!cvTermIsHidden(mdbVar->var)) { char *label = (char *)cvLabel(NULL,mdbVar->var); char *linkOfType = wgEncodeVocabLink(CV_TYPE,mdbVar->var,label, label,NULL); if (cvTermIsCvDefined(mdbVar->var)) { label = (char *)cvLabel(mdbVar->var,mdbVar->val); char *linkOfTerm = wgEncodeVocabLink(CV_TERM,mdbVar->val,label, label,NULL); dyStringPrintf(dyTable,"", linkOfType,linkOfTerm); freeMem(linkOfTerm); } else dyStringPrintf(dyTable,"", linkOfType,mdbVar->val); freeMem(linkOfType); continue; } } } dyStringPrintf(dyTable,"" "",mdbVar->var,mdbVar->val); } } dyStringAppend(dyTable,"
%s
shortLabel:%s
%s:",mdbVar->var); struct slName *fileSet = slNameListFromComma(mdbVar->val); while (fileSet != NULL) { struct slName *file = slPopHead(&fileSet); dyStringAppend(dyTable,htmlStringForDownloadsLink(db, tdb, file->name, TRUE)); if (fileSet != NULL) dyStringAppend(dyTable,"
"); slNameFree(&file); } dyStringAppend(dyTable,"
" "%s:%s
" "%s:%s
%s:%s
"); //mdbObjsFree(&mdbObj); // spill some memory return dyStringCannibalize(&dyTable); } boolean compositeMetadataToggle(char *db,struct trackDb *tdb,char *title, boolean embeddedInText,boolean showLongLabel) // If metadata from metaTbl exists, create a link that will allow toggling it's display { boolean hasMetaInHub = (trackDbSetting(tdb, "metaDb") != NULL) || (trackDbSetting(tdb, "metaTab") != NULL); if (!hasMetaInHub) { const struct mdbObj *safeObj = metadataForTable(db,tdb,NULL); if (safeObj == NULL || safeObj->vars == NULL) return FALSE; } char id[256]; safef(id, sizeof id, "div_%s_link", tdb->track); printf("%s%s", (embeddedInText?" ":"

"),id,tdb->track, (title?title:"")); jsOnEventByIdF("click", id, "return metadataShowHide(\"%s\",%s,true);", tdb->track, showLongLabel?"true":"false"); printf("

",tdb->track, metadataAsHtmlTable(db,tdb,showLongLabel,FALSE)); return TRUE; } /* Multi-region UI */ boolean makeMultiRegionLink(char *db, struct trackDb *tdb, struct cart *cart) /* Make a link to launch browser in multi-region custom URL mode, based on * track setting. This includes creating a custom track displaying the regions. * The link switches to exit multi-region if browser is already in multi-region mode * based on regions defined for this track. */ { char *regionUrl = trackDbSetting(tdb, "multiRegionsBedUrl"); if (isEmpty(regionUrl)) return FALSE; // make custom track for regions, alternating colors // TODO: truncate CT name and label at word boundary // TODO: fix bedPackDense to work with multi-region // TODO: limit number of regions ? struct dyString *dsCustomText = dyStringCreate( "track name=\'%s ROI\' description=\'[Regions of Interest] %s' " "visibility=dense bedPackDense=on labelOnFeature=on itemRgb=on noScoreFilter=on\n", tdb->shortLabel, tdb->longLabel); #ifdef LATER // TODO: libify struct dyString *ds = NULL; struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { int sd = netUrlOpen(regionUrl); if (sd >= 0) { char *newUrl = NULL; int newSd = 0; if (netSkipHttpHeaderLinesHandlingRedirect(sd, regionUrl, &newSd, &newUrl)) { if (newUrl) /* redirect can modify the url */ { freeMem(newUrl); sd = newSd; } ds = netSlurpFile(sd); close(sd); } } } errCatchEnd(errCatch); if (errCatch->gotError) warn("%s", errCatch->message->string); // how come no warning if bad file ? errCatchFree(&errCatch); #endif // TODO: support $D, etc. in URL int sd = netUrlOpen(regionUrl); if (sd < 0) return FALSE; struct dyString *dsRegionBed = netSlurpFile(sd); close(sd); if (!dsRegionBed) return FALSE; char *regionBedTxt = dyStringCannibalize(&dsRegionBed); // count fields in BED. Accept up to BED9 (user-spec colors) char *bedTxt = cloneString(regionBedTxt); struct lineFile *lf = lineFileOnString(NULL, TRUE, bedTxt); char *words[9]; int bedSize = lineFileChopNext(lf, words, sizeof words); lineFileClose(&lf); freeMem(bedTxt); lf = lineFileOnString(NULL, TRUE, regionBedTxt); // TODO: refactor with interact multi-region static char *colorLight = "184,201,255"; // blue static char *colorDark = "0,0,0"; // black char *color = colorLight; boolean doLightColor = TRUE; int id = 1; char name[100]; char userColor[10]; struct bed *region; struct tempName mrTn; trashDirFile(&mrTn, "hgt", "custRgn_track", ".bed"); FILE *f = fopen(mrTn.forCgi, "w"); if (f == NULL) errAbort("can't create temp file %s", mrTn.forCgi); char regionInfo[1024]; char *regionFile = cloneString(mrTn.forCgi); // TODO: trackDb setting ? #define MULTI_REGION_BED_DEFAULT_PADDING 1000 int padding = MULTI_REGION_BED_DEFAULT_PADDING; safef(regionInfo, sizeof regionInfo, "#padding %d\n", padding); mustWrite(f, regionInfo, strlen(regionInfo)); #ifdef LATER safef(regionInfo, sizeof regionInfo, "#shortDesc %s\n", name); mustWrite(f, regionInfo, strlen(regionInfo)); #endif // write to trash file and custom track int regionCount = 0; while (lineFileChopNext(lf, words, bedSize)) { region = bedLoadN(words, bedSize); if (bedSize < 9) { // assign alternating light/dark color color = doLightColor ? colorLight : colorDark; doLightColor = !doLightColor; } else { struct rgbColor rgb = bedColorToRgb(region->itemRgb); safef(userColor, sizeof userColor, "%d,%d,%d", rgb.r, rgb.g, rgb.b); } if (bedSize < 4) { // region label based on chrom and an item number safef(name, sizeof name, "r%d/%s", id++, region->chrom); } else { strcpy(name, region->name); } // write to trash file safef(regionInfo, sizeof regionInfo, "%s\t%d\t%d\n", region->chrom, region->chromStart, region->chromEnd); mustWrite(f, regionInfo, strlen(regionInfo)); // write to custom track int start = max(region->chromStart - padding, 0); int end = min(region->chromEnd + padding, hChromSize(db, region->chrom)); dyStringPrintf(dsCustomText, "%s\t%d\t%d\t%s\t" "0\t.\t%d\t%d\t%s\n", region->chrom, start, end, name, start, end, color); regionCount++; } lineFileClose(&lf); fclose(f); // create SHA1 file; used to see if file has changed unsigned char hash[SHA_DIGEST_LENGTH]; SHA1((const unsigned char *)regionInfo, strlen(regionInfo), hash); char newSha1[(SHA_DIGEST_LENGTH + 1) * 2]; hexBinaryString(hash, SHA_DIGEST_LENGTH, newSha1, (SHA_DIGEST_LENGTH + 1) * 2); char sha1File[1024]; safef(sha1File, sizeof sha1File, "%s.sha1", mrTn.forCgi); f = mustOpen(sha1File, "w"); mustWrite(f, newSha1, strlen(newSha1)); carefulClose(&f); char customHtml[1000]; safef(customHtml, sizeof customHtml, "

Description

\n" "

This custom track displays regions of interest for the " "%s track.

", db, tdb->track, tdb->shortLabel); // TODO: support #padding in custom regions file enum trackVisibility vis = hTvFromString(cartUsualString(cart, tdb->track, hStringFromTv(tdb->visibility))); if (vis == tvHide) vis = tvDense; printf("

"); printf("" "Display regions of interest (%d)", MULTI_REGION_BED_WIN_FULL, tdb->track, cgiEncode(regionFile), tdb->track, hStringFromTv(vis), CT_CUSTOM_DOC_TEXT_VAR, cgiEncode(customHtml), CT_CUSTOM_TEXT_VAR, cgiEncode(dyStringCannibalize(&dsCustomText)), regionCount); printf(" in multi-region view (custom regions mode)"); printf("   "); printf("(Help)\n"); printf("

"); return TRUE; } static void printDownloadUrl(char *downloadUrl, char *database, char *track) /* given a string