f57fc11d951807e19b20b5960e735fa50eaea279 braney Fri Jun 12 13:10:00 2026 -0700 Fix more warnings exposed by -O3 build across hg utils and errAbort Continuation of the -O3 cleanup: a full clean rebuild surfaced warnings in many programs whose objects had not been recompiled before. Most are the same mechanical patterns as the first batch (strncpy -> safecpy/memcpy, sprintf -> safef), plus a few that needed more thought: - errAbort.h: mark errAbort/vaErrAbort/errnoAbort/noWarnAbort as noreturn. They provably never return (longjmp or exit; the existing "to make compiler happy" exit(-1) in noWarnAbort confirms the intent), and this lets GCC prune the impossible null paths after an errAbort guard, fixing false-positive null-deref / overread warnings in mafAddIRows, mafAddIRowsStream and phyloPlace with no source change to those files. - altSplice.c (hgGene): real one-element stack buffer overflow. makeGrayShades writes shadesOfGray[maxShade+1], but the caller declared shadesOfGray[9] with maxShade=8. Grow the array to [10] (maxShade stays 8); behavior unchanged. - hgc.c bedPrintPos: ~60 callers pass a track-specific struct cast to (struct bed *) and read only its bed-compatible leading fields. At -O3 -Warray-bounds flags the casts because the real object is smaller than struct bed; the reads are safe by the bed-layout convention, so suppress -Warray-bounds around just that function. - mafsInRegion.c: chromFromSrc returns strchr(src,'.')+1, which GCC mis-sizes as a 0-byte region when handed to strcmp via sameString/differentString; suppress the false-positive -Wstringop-overread around extractMafs. - sanger22gtf.c, bottleneck.c: put the printf/fprintf in the else of the NULL guard so -Wformat-overflow (which runs before the noreturn-based pruning) can see the argument is non-null. safecpy/memcpy/safef conversions: basicBed already done earlier; here haplotypes (memcpy of the original pointer pun), gbToFaRa, motifSig, hgClonePos, featureBits, libScan, hgGoldGapGl, hgSoftPromoter, mafClick, mafAddQRows, hgc.c, stanToBedAndExpRecs, bedUp, faSplit, trfBig, splitFaIntoContigs, aladdin, ameme. A full clean tree now builds with no warnings at -O3. refs #37761 Co-Authored-By: Claude Opus 4.8 (1M context) diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c index bc3905e0bc2..5c0bfcd230a 100644 --- src/hg/hgc/hgc.c +++ src/hg/hgc/hgc.c @@ -802,57 +802,64 @@ void samplePrintPos(struct sample *smp, int smpSize) /* Print first three fields of a sample 9 type structure in * standard format. */ { if ( smpSize != 9 ) errAbort("Invalid sample entry!\n It has %d fields instead of 9\n", smpSize); printf("Item: %s
\n", smp->name); printf("Score: %d
\n", smp->score); printf("Strand: %s
\n", smp->strand); printPos(smp->chrom, smp->chromStart, smp->chromEnd, NULL, TRUE, smp->name); } +// Many callers pass a track-specific struct cast to (struct bed *), relying on +// its bed-compatible leading fields (only the first bedSize fields are read). +// At -O3 GCC's -Warray-bounds flags those casts because the real object is +// smaller than struct bed; the accesses are safe by the bed-layout convention. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" void bedPrintPos(struct bed *bed, int bedSize, struct trackDb *tdb) /* Print first bedSize fields of a bed type structure in * standard format. */ { char *strand = NULL; if (bedSize >= 4 && bed->name[0] != 0) { char *label = "Item", *tdbLabel = NULL; if (tdb && ((tdbLabel = trackDbSetting(tdb, "bedNameLabel")) != NULL)) label = tdbLabel; printf("%s: %s
\n", label, bed->name); } if (bedSize >= 5) { if (!tdb || !trackDbSetting(tdb, "noScoreFilter")) { char *scoreLabel = trackDbSettingOrDefault(tdb, "scoreLabel", "Score"); printf("%s: %d
\n", scoreLabel, bed->score); } } if (bedSize >= 6) { strand = bed->strand; } printPos(bed->chrom, bed->chromStart, bed->chromEnd, strand, TRUE, bed->name); } +#pragma GCC diagnostic pop void genericHeader(struct trackDb *tdb, char *item) /* Put up generic track info. */ { if (item != NULL && item[0] != 0) cartWebStart(cart, database, "%s: %s (%s)", genome, tdb->longLabel, item); else cartWebStart(cart, database, "%s: %s", genome, tdb->longLabel); // QA noticed that clicking the +- buttons to collapse item detail tables was // generating messages in the Apache log if you went directly to an item page // without first visiting hgTracks. Clicking those buttons causes a cartDump // in order to save the state of visibility of the table, which in // turn needs an hgsid in order to save the state correctly. However, because // we aren't in a form, we have never saved the hgsid to a hidden @@ -13896,31 +13903,31 @@ printAlignments(pslList, start, "htcCdnaAli", "HInvGeneMrna", item); printTrackHtml(tdb); hFreeConn(&conn); } char *getGi(char *ncbiFaHead) /* Get GI number from NCBI FA format header. */ { char *s; static char gi[64]; if (!startsWith("gi|", ncbiFaHead)) return NULL; ncbiFaHead += 3; -strncpy(gi, ncbiFaHead, sizeof(gi)); +safecpy(gi, sizeof(gi), ncbiFaHead); s = strchr(gi, '|'); if (s != NULL) *s = 0; return trimSpaces(gi); } void showSAM_T02(char *itemName) { char query2[256]; struct sqlResult *sr2; char **row2; struct sqlConnection *conn2 = hAllocConn(database); char cond_str[256]; char *predFN; char *homologID; @@ -15841,37 +15848,37 @@ sqlSafef(query, sizeof(query), "select * from %s where name = '%s' and chrom = '%s' ", table, name, qChrom ); sr = sqlGetResult(conn2, query); if ((row = sqlNextRow(sr)) != NULL) gp = genePredLoad(row + hasBin); sqlFreeResult(&sr); } if (gp == NULL) errAbort("htcPseudoGene: Could not locate gene prediction (db=%s, table=%s, name=%s, in range %s:%d-%d) %s", db2, table, name, qChrom, qStart+1, qEnd, query); /* extract nib directory from nibfile */ if (strrchr(nibFile,'/') != NULL) - strncpy(tNibDir, nibFile, strlen(nibFile)-strlen(strrchr(nibFile,'/'))); + memcpy(tNibDir, nibFile, strlen(nibFile)-strlen(strrchr(nibFile,'/'))); else errAbort("Cannot find nib directory for %s\n",nibFile); tNibDir[strlen(nibFile)-strlen(strrchr(nibFile,'/'))] = '\0'; if (strrchr(qNibFile,'/') != NULL) - strncpy(qNibDir, qNibFile, strlen(qNibFile)-strlen(strrchr(qNibFile,'/'))); + memcpy(qNibDir, qNibFile, strlen(qNibFile)-strlen(strrchr(qNibFile,'/'))); else errAbort("Cannot find nib directory for %s\n",qNibFile); qNibDir[strlen(qNibFile)-strlen(strrchr(qNibFile,'/'))] = '\0'; safef(path, sizeof path, "%s/%s.nib", tNibDir, chrom); /* load chain */ if (sameString(database,db2)) { track = "selfChain"; if (!hTableExists(database, "chr1_selfChain")) track = "chainSelf"; } else { @@ -25067,31 +25074,31 @@ char *table = tdb->table; struct dvBed dvBed; struct dv *dv; struct dvXref2 *dvXref2; struct omimTitle *omimTitle; struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr, *sr2, *sr3, *sr4; char **row; char query[256], query2[256], query3[256], query4[256]; int rowOffset = hOffsetPastBin(database, seqName, table); int start = cartInt(cart, "o"); genericHeader(tdb, itemName); -printf("Item: %s
\n", itemName); +printf("Item: %s
\n", naForNull(itemName)); printf("Outside Link: "); printf(" %s
\n", itemName); sqlSafef(query, sizeof(query), "select * from %s where chrom = '%s' and " "chromStart=%d and name = '%s'", table, seqName, start, itemName); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { dvBedStaticLoad(row+rowOffset, &dvBed); bedPrintPos((struct bed *)&dvBed, 3, tdb); } sqlFreeResult(&sr);