[PROPOSED 1/3] Pacify gcc -Wsuggest-attribute=format sans snprintf in zdump

* zdump.c (my_snprintf): Now a static function defined only if !HAVE_SNPRINTF, with "#define snprintf my_sprintf" at the end. This lessens disruption to mainline code. All uses changed. Add ATTRIBUTE_FORMAT((printf, 3, 4)) to pacify gcc -Wsuggest-attribute=format. --- zdump.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/zdump.c b/zdump.c index c988f6b3..ea051adf 100644 --- a/zdump.c +++ b/zdump.c @@ -914,13 +914,10 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) } } -#if HAVE_SNPRINTF -# define my_snprintf snprintf -#else +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF # include <stdarg.h> - -/* A substitute for snprintf that is good enough for zdump. */ -static int +ATTRIBUTE_FORMAT((printf, 3, 4)) static int my_snprintf(char *s, size_t size, char const *format, ...) { int n; @@ -948,6 +945,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) va_end(args); return n; } +# define snprintf my_snprintf #endif /* Store into BUF, of size SIZE, a formatted local time taken from *TM. @@ -962,10 +960,10 @@ format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) { int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; return (ss - ? my_snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) + ? snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) : mm - ? my_snprintf(buf, size, "%02d:%02d", hh, mm) - : my_snprintf(buf, size, "%02d", hh)); + ? snprintf(buf, size, "%02d:%02d", hh, mm) + : snprintf(buf, size, "%02d", hh)); } /* Store into BUF, of size SIZE, a formatted UT offset for the @@ -1000,10 +998,10 @@ format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) mm = off / 60 % 60; hh = off / 60 / 60; return (ss || 100 <= hh - ? my_snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) + ? snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) : mm - ? my_snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) - : my_snprintf(buf, size, "%c%02ld", sign, hh)); + ? snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) + : snprintf(buf, size, "%c%02ld", sign, hh)); } /* Store into BUF (of size SIZE) a quoted string representation of P. @@ -1106,7 +1104,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, for (abp = ab; is_alpha(*abp); abp++) continue; len = (!*abp && *ab - ? my_snprintf(b, s, "%s", ab) + ? snprintf(b, s, "%s", ab) : format_quoted_string(b, s, ab)); if (s <= len) return false; @@ -1114,7 +1112,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, } formatted_len = (tm->tm_isdst - ? my_snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) + ? snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) : 0); } break; -- 2.43.0

* asctime.c (my_snprintf, snprintf) [!HAVE_SNPRINTF]: New function and macro. (SNPRINTF, SNPRINTF_BUF): Remove. All uses replaced by plain snprintf. This lessens disruption to mainline code and ports better to NetBSD, which does "#define snprintf" to something else that collides with how SNPRINTF works. --- asctime.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/asctime.c b/asctime.c index 51ce5a50..b4424de4 100644 --- a/asctime.c +++ b/asctime.c @@ -40,6 +40,26 @@ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; static char buf_ctime[sizeof buf_asctime]; #endif +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF +# include <stdarg.h> +ATTRIBUTE_FORMAT((printf, 3, 4)) static int +my_snprintf(char *s, size_t size, char const *format, ...) +{ + int n; + va_list args; + char stackbuf[sizeof buf_asctime]; + va_start(args, format); + n = vsprintf(stackbuf, format, args); + va_end (args); + if (0 <= n && n < size) + memcpy (s, stackbuf, n + 1); + return n; +} +# undef snprintf +# define snprintf my_snprintf +#endif + /* Publish asctime_r and ctime_r only when supporting older POSIX. */ #if SUPPORT_POSIX2008 # define asctime_static @@ -68,16 +88,6 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) size_t bufsize = ((buf == buf_ctime || (!SUPPORT_C89 && buf == buf_asctime)) ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE); -#if HAVE_SNPRINTF - char *result = buf; -# define SNPRINTF snprintf -# define SNPRINTFBUF(buf, bufsize) buf, bufsize -#else - char stackbuf[sizeof buf_asctime]; - char *result = stackbuf; -# define SNPRINTF sprintf -# define SNPRINTFBUF(buf, bufsize) buf -#endif if (timeptr == NULL) { strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); @@ -113,25 +123,21 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */ if ((year <= INT_MAX - TM_YEAR_BASE - ? SNPRINTF (SNPRINTFBUF(result, bufsize), + ? snprintf (buf, bufsize, ((-999 - TM_YEAR_BASE <= year && year <= 9999 - TM_YEAR_BASE) ? "%s %s%3d %.2d:%.2d:%.2d %04d\n" : "%s %s%3d %.2d:%.2d:%.2d %d\n"), wn, mn, mday, hour, min, sec, year + TM_YEAR_BASE) - : SNPRINTF (SNPRINTFBUF(result, bufsize), + : snprintf (buf, bufsize, "%s %s%3d %.2d:%.2d:%.2d %d%d\n", wn, mn, mday, hour, min, sec, year / 10 + TM_YEAR_BASE / 10, year % 10)) - < bufsize) { -#if HAVE_SNPRINTF + < bufsize) return buf; -#else - return strcpy(buf, result); -#endif - } else { + else { errno = EOVERFLOW; return NULL; } -- 2.43.0

* Makefile (GCC_DEBUG_FLAGS): Add -Wno-type-limits, which is needed again even with GCC 14, due to the following change. * asctime.c (asctime_r): On platforms where INT_MAX < LONG_MAX, help the compiler optimize away a runtime check, and to optimize away the need to have two static calls to snprintf. --- Makefile | 2 +- asctime.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index e8574551..5473dedd 100644 --- a/Makefile +++ b/Makefile @@ -337,7 +337,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ -Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ - -Wno-format-nonliteral -Wno-sign-compare + -Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), diff --git a/asctime.c b/asctime.c index b4424de4..3817182e 100644 --- a/asctime.c +++ b/asctime.c @@ -85,6 +85,7 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) register const char * wn; register const char * mn; int year, mday, hour, min, sec; + long long_TM_YEAR_BASE = TM_YEAR_BASE; size_t bufsize = ((buf == buf_ctime || (!SUPPORT_C89 && buf == buf_asctime)) ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE); @@ -122,14 +123,14 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */ - if ((year <= INT_MAX - TM_YEAR_BASE + if ((year <= LONG_MAX - TM_YEAR_BASE ? snprintf (buf, bufsize, ((-999 - TM_YEAR_BASE <= year && year <= 9999 - TM_YEAR_BASE) - ? "%s %s%3d %.2d:%.2d:%.2d %04d\n" - : "%s %s%3d %.2d:%.2d:%.2d %d\n"), + ? "%s %s%3d %.2d:%.2d:%.2d %04ld\n" + : "%s %s%3d %.2d:%.2d:%.2d %ld\n"), wn, mn, mday, hour, min, sec, - year + TM_YEAR_BASE) + year + long_TM_YEAR_BASE) : snprintf (buf, bufsize, "%s %s%3d %.2d:%.2d:%.2d %d%d\n", wn, mn, mday, hour, min, sec, -- 2.43.0
participants (1)
-
Paul Eggert