#770 removed the index form x[strlen(x) - 1]. The pointer form is still there: x + strlen(x) - 1 builds a pointer one byte before the buffer when the string is empty, which is undefined even before anyone reads through it.
25 occurrences on master, 13 of them in htsname.c.
Two already carry a hand-written guard. lienrelatif got a ternary in #729, htsAddLink got the same ternary in #767:
// empty codebase has no last char; codebase-1 would underflow
a = codebase[0] != '\0' ? codebase + strlen(codebase) - 1 : codebase;
That is the per-site guard #770 set out to remove. The other 23 have nothing on the line, though some are protected further up, so this wants the same classification pass #770 did rather than a blanket rewrite.
Fix follows #770: a helper next to hts_lastchar/hts_striplastchar/hts_choplastchar in src/htssafe.h that returns the address of the last character and handles the empty case once.
htsstrings.h carries the same shape on the String type and is worth folding in: StringRight(BLK, POS) and StringPopRight(BLK) are both documented as having no bounds check.
#770 removed the index form
x[strlen(x) - 1]. The pointer form is still there:x + strlen(x) - 1builds a pointer one byte before the buffer when the string is empty, which is undefined even before anyone reads through it.25 occurrences on master, 13 of them in
htsname.c.Two already carry a hand-written guard.
lienrelatifgot a ternary in #729,htsAddLinkgot the same ternary in #767:That is the per-site guard #770 set out to remove. The other 23 have nothing on the line, though some are protected further up, so this wants the same classification pass #770 did rather than a blanket rewrite.
Fix follows #770: a helper next to
hts_lastchar/hts_striplastchar/hts_choplastcharinsrc/htssafe.hthat returns the address of the last character and handles the empty case once.htsstrings.hcarries the same shape on theStringtype and is worth folding in:StringRight(BLK, POS)andStringPopRight(BLK)are both documented as having no bounds check.