In doabbr(), the zone line's FORMAT field (zp->z_format) was passed directly as the format argument of sprintf(): sprintf(abbr, format, letters); FORMAT comes from zone data, which is not always trusted: zic is also used to compile third-party or user-supplied zone description files. Passing such data as a printf format string is the classic uncontrolled-format-string anti-pattern (CWE-134 / CERT FIO30-C), and it is what makes this line the sole -Wformat-nonliteral warning in doabbr under -Wformat=2. inzsub() already restricts a slash-less FORMAT to at most one '%s' conversion (a '%z' is rewritten to '%s' earlier), so expand that lone conversion explicitly with mempcpy()/strcpy() instead of handing the data to sprintf(). This removes the format-string sink while keeping the output byte-for-byte identical for every valid FORMAT, so the generated TZif files are unchanged. * zic.c (doabbr): Expand FORMAT's single '%s' by hand rather than using FORMAT as a printf format string. --- diff --git a/zic.c b/zic.c index af2bb80..7cc48ef 100644 --- a/zic.c +++ b/zic.c @@ -3135,7 +3135,15 @@ doabbr(char *abbr, struct zone const *zp, char const *letters, letters = "%s"; else if (letters == disable_percent_s) return 0; - sprintf(abbr, format, letters); + /* Expand FORMAT's lone "%s" (see inzsub) without treating + FORMAT, which comes from zone data, as a printf format string. */ + cp = strchr(format, '%'); + if (cp) { + char *dp = mempcpy(abbr, format, cp - format); + dp = mempcpy(dp, letters, strlen(letters)); + strcpy(dp, cp + 2); + } else + strcpy(abbr, format); } else if (isdst) strcpy(abbr, slashp + 1); else { -- 2.50.1 (Apple Git-155)