a71215bcc4a26e1641770d82127dc57ced1842c8 braney Tue Mar 10 12:37:04 2026 -0700 Detect tracks that list themselves as their own parent, preventing infinite loop refs #35986 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> diff --git src/hg/lib/trackDbCustom.c src/hg/lib/trackDbCustom.c index 89704f273bd..17e20d596a7 100644 --- src/hg/lib/trackDbCustom.c +++ src/hg/lib/trackDbCustom.c @@ -646,30 +646,35 @@ /* adjust settings on supertrack members after verifying they have * a supertrack configured in this trackDb */ for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { if (tdbIsSuperTrack(tdb) || tdb->parent != NULL) continue; setting = trackDbLocalSetting(tdb, "parent"); if (!setting) setting = trackDbLocalSetting(tdb, "superTrack"); // Old style if (!setting) continue; wordCt = chopLine(cloneString(setting), words); assert(differentString("on", words[0])); // already weeded out "superTrack on" char *parentName = maybeSkipHubPrefix(words[0]); tdb->parent = hashFindVal(superHash, parentName); + if (tdb->parent == tdb) + { + warn("Track %s lists itself as its own parent, ignoring.", tdb->track); + tdb->parent = NULL; + } if (tdb->parent) { tdbMarkAsSuperTrackChild(tdb); tdb->parentName = cloneString(parentName); if (wordCt > 1) tdb->visibility = max(0, hTvFromStringNoAbort(words[1])); } freeMem(words[0]); } hashFree(&superHash); } char *trackDbOrigAssembly(struct trackDb *tdb) /* return setting from trackDb, if any */ { @@ -1030,30 +1035,32 @@ if (tdbIsSuperTrack(tdb)) tdb->next = NULL; else slAddHead(&superlessList, tdb); } /* Do subtrack hierarchy - filling in parent and subtracks fields. */ for (tdb = superlessList; tdb != NULL; tdb = next) { next = tdb->next; char *subtrackSetting = trackDbLocalSetting(tdb, "parent"); if (subtrackSetting != NULL && !tdbIsSuperTrackChild(tdb)) // superChildren cannot be in both subtracks list AND tdbList { char *parentName = cloneFirstWord(subtrackSetting); + if (sameString(parentName, tdb->track)) + errAbort("Track %s lists itself as its own parent", tdb->track); struct trackDb *parent = hashFindVal(trackHash, parentName); if (parent != NULL) { if (trackDbLocalSetting(tdb, "container")) { errAbort("Composite track '%s' cannot have child track '%s'," " which is a container multiWig.", parentName, tdb->track); } slAddHead(&parent->subtracks, tdb); // composite/multiWig children are ONLY subtracks tdb->parent = parent; } else { errAbort("Parent track %s of child %s doesn't exist", parentName, tdb->track); }