dd59061711dca60f7fe8f430411b8c5eb7559d4a
braney
  Fri Jun 12 14:48:21 2026 -0700
lib/tests: fix -O3 format-overflow in mmHashTest

Put the fprintf in the else of the NULL guard so -Wformat-overflow (which
runs before the noreturn-based pruning) sees the value is non-null.  Same
pattern as the earlier sanger22gtf/bottleneck fixes.

This surfaced only now because make clean does not clean most test
directories, so the test programs kept reusing stale -O -g objects until a
forced rebuild recompiled them at -O3.

refs #37761

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

diff --git src/lib/tests/mmHashTest.c src/lib/tests/mmHashTest.c
index f0654ebf1ee..7fa06ab5400 100644
--- src/lib/tests/mmHashTest.c
+++ src/lib/tests/mmHashTest.c
@@ -1,105 +1,106 @@
 /* mmHashTest - Make a hash of strings, write an mmHash file, memory-map it and look up items. */
 
 /* Copyright (C) 2024 The Regents of the University of California
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #include "common.h"
 #include "linefile.h"
 #include "mmHash.h"
 #include "options.h"
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
   "mmHashTest - Make a hash of strings, write an mmHash file, memory-map it and look up items.\n"
   "usage:\n"
   "  mmHashTest in.txt out.mmh out.txt\n"
   "Each line of in.txt contains a key followed by a tab character followed by a value.\n"
   "in.txt is read into a hash which is converted to mmHash and written out to out.mmh.\n"
   "out.mmh is read back in as a memory-mapped file, items are looked up and written to out.txt.\n"
   "out.txt should contain the same contents as in.txt unless there are multiple lines with\n"
   "the same key; in that case, only the last line with the key will be included in out.txt.\n"
   );
 }
 
 static struct optionSpec options[] = {
     {NULL, 0},
 };
 
 static void makeRandomString(char *buf, int bufSize)
 /* Fill buf with bufSize-1 random printable characters and 0-terminate. */
 {
 // Use as printable characters: ASCII 32-126
 int i;
 for (i = 0;  i < bufSize-1;  i++)
     buf[i] = 32 + (rand() % 95);
 buf[bufSize-1] = 0;
 }
 
 void mmHashTest(char *inFileName, char *mmHashFileName, char *outFileName)
 /* Read in items from a file and print the resulting clusters. */
 {
 FILE *f = mustOpen(outFileName, "w");
 // Read inFile into hash
 struct lineFile *lf = lineFileOpen(inFileName, TRUE);
 struct hash *hash = hashNew(0);
 struct slName *keyList = NULL;
 char *line;
 int size;
 while (lineFileNext(lf, &line, &size))
     {
     char *key = line;
     char *val = "";
     char *tab = strchr(line, '\t');
     if (tab != NULL)
         {
         *tab = '\0';
         val = tab + 1;
         }
     hashAdd(hash, key, cloneString(val));
     slNameAddHead(&keyList, key);
     }
 lineFileClose(&lf);
 slReverse(&keyList);
 
 // Convert hash to mmHash file.
 hashToMmHashFile(hash, mmHashFileName);
 freeHashAndVals(&hash);
 
 // Get that file memory-mapped.
 struct mmHash *mmh = mmHashFromFile(mmHashFileName);
 
 // Just for fun, look up a long random name, with the expectation that there is no way it will
 // ever appear in input, to make sure that when a key is not found, we return NULL instead of
 // crashing or returning a value.
 char longRandomString[512];
 makeRandomString(longRandomString, sizeof longRandomString);
 const char *shouldBeNull = mmHashFindVal(mmh, longRandomString);
 if (shouldBeNull != NULL)
     errAbort("Error: I really did not expect to find the following line as a key in %s:\n%s\n"
              "-- but there it was, with a value of '%s'",
              inFileName, longRandomString, shouldBeNull);
 
 // Look up and write out all the items.
 struct slName *key;
 for (key = keyList;  key != NULL;  key = key->next)
     {
     const char *val = mmHashFindVal(mmh, key->name);
     if (val == NULL)
         errAbort("Lookup of key '%s' failed.", key->name);
+    else
         fprintf(f, "%s\t%s\n", key->name, val);
     }
 carefulClose(&f);
 }
 
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 optionInit(&argc, argv, options);
 if (argc != 4)
     usage();
 mmHashTest(argv[1], argv[2], argv[3]);
 return 0;
 }