diff options
author | Alexander Amelkin <alexander@amelkin.msk.ru> | 2018-09-14 14:24:35 +0300 |
---|---|---|
committer | Alexander Amelkin <alexander@amelkin.msk.ru> | 2018-11-07 18:50:10 +0300 |
commit | 4f05b95f6c3d6daa46c58f64a75669f47b679718 (patch) | |
tree | 506878d708be6397c6ba6a18aa0b387165c0a124 /lib | |
parent | f0d5c17ea7b2b5b815f24b101d35ddda1a88d8a4 (diff) | |
download | ipmitool-4f05b95f6c3d6daa46c58f64a75669f47b679718.tar.gz |
Fix strftime() non-literal argument warning
There is a bug in gcc since 4.3.2 and still not fixed in 8.1.0.
Even if __attribute__((format(strftime... is specified for a
wrapper function around strftime, gcc still complains about strftime
being called from the wrapper with a "non-literal" format argument.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39438
This commit adds 'ugly hacks' from that discussion to call strftime()
from strftime-formatted wrappers and silence the warnings.
Partially resolves ipmitool/ipmitool#23
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ipmi_time.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/lib/ipmi_time.c b/lib/ipmi_time.c index f2e01be..aecd656 100644 --- a/lib/ipmi_time.c +++ b/lib/ipmi_time.c @@ -68,9 +68,25 @@ ipmi_localtime2utc(time_t local) * @returns the number of bytes written to s or 0, see strftime() */ size_t -ipmi_strftime(char *s, int max, const char *format, time_t stamp) +ipmi_strftime(char *s, size_t max, const char *format, time_t stamp) { struct tm tm; + /* + * There is a bug in gcc since 4.3.2 and still not fixed in 8.1.0. + * Even if __attribute__((format(strftime... is specified for a wrapper + * function around strftime, gcc still complains about strftime being + * called from the wrapper with a "non-literal" format argument. + * + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39438 + * + * The following macro uses an "ugly cast" from that discussion to + * silence the compiler. The format string is checked for the wrapper + * because __attribute__((format)) is specified in the header file. + */ + #define wrapstrftime(buf, buflen, fmt, t) \ + ((size_t (*)(char *, size_t, const char *, const struct tm *))\ + strftime)(buf, buflen, fmt, t) + if (IPMI_TIME_UNSPECIFIED == stamp) { return snprintf(s, max, "Unknown"); @@ -79,7 +95,7 @@ ipmi_strftime(char *s, int max, const char *format, time_t stamp) /* Timestamp is relative to BMC start, no GMT offset */ gmtime_r(&stamp, &tm); - return strftime(s, max, format, &tm); + return wrapstrftime(s, max, format, &tm); } if (time_in_utc || ipmi_timestamp_is_special(stamp)) { @@ -96,7 +112,7 @@ ipmi_strftime(char *s, int max, const char *format, time_t stamp) */ localtime_r(&stamp, &tm); } - return strftime(s, max, format, &tm); + return wrapstrftime(s, max, format, &tm); } /** @@ -115,21 +131,20 @@ ipmi_strftime(char *s, int max, const char *format, time_t stamp) char * ipmi_asctime_r(const time_t stamp, ipmi_datebuf_t outbuf) { - const char *format = "%c %Z"; if (ipmi_timestamp_is_special(stamp)) { if (stamp < SECONDS_A_DAY) { - format = "S+%H:%M:%S"; + ipmi_strftime(outbuf, IPMI_ASCTIME_SZ, "S+%H:%M:%S", stamp); } /* * IPMI_TIME_INIT_DONE is over 17 years. This should never * happen normally, but we'll support this anyway. */ else { - format = "S+%yy %jd %H:%M:%S"; + ipmi_strftime(outbuf, IPMI_ASCTIME_SZ, "S+%yy %jd %H:%M:%S", stamp); } } - ipmi_strftime(outbuf, IPMI_ASCTIME_SZ, format, stamp); + ipmi_strftime(outbuf, IPMI_ASCTIME_SZ, "%c %Z", stamp); return outbuf; } @@ -141,68 +156,79 @@ ipmi_timestamp_fmt(uint32_t stamp, const char *fmt) * than IPMI_ASCTIME_SZ */ static ipmi_datebuf_t datebuf; - ipmi_strftime(datebuf, sizeof(datebuf), fmt, stamp); + /* + * There is a bug in gcc since 4.3.2 and still not fixed in 8.1.0. + * Even if __attribute__((format(strftime... is specified for a wrapper + * function around strftime, gcc still complains about strftime being + * called from the wrapper with a "non-literal" format argument. + * + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39438 + * + * The following call uses an "ugly cast" from that discussion to + * silence the compiler. The format string is checked for the wrapper + * because __attribute__((format)) is specified in the header file. + */ + ((size_t (*)(char *, size_t, const char *, time_t)) + ipmi_strftime)(datebuf, sizeof(datebuf), fmt, stamp); + return datebuf; } char * ipmi_timestamp_string(uint32_t stamp) { - const char *format = "%c %Z"; if (!ipmi_timestamp_is_valid(stamp)) { return "Unspecified"; } if (ipmi_timestamp_is_special(stamp)) { if (stamp < SECONDS_A_DAY) { - format = "S+ %H:%M:%S"; + return ipmi_timestamp_fmt(stamp, "S+ %H:%M:%S"); } /* * IPMI_TIME_INIT_DONE is over 17 years. This should never * happen normally, but we'll support this anyway. */ else { - format = "S+ %y years %j days %H:%M:%S"; + return ipmi_timestamp_fmt(stamp, "S+ %y years %j days %H:%M:%S"); } } - return ipmi_timestamp_fmt(stamp, format); + return ipmi_timestamp_fmt(stamp, "%c %Z"); } char * ipmi_timestamp_numeric(uint32_t stamp) { - const char *format = "%x %X %Z"; if (!ipmi_timestamp_is_valid(stamp)) { return "Unspecified"; } if (ipmi_timestamp_is_special(stamp)) { if (stamp < SECONDS_A_DAY) { - format = "S+ %H:%M:%S"; + return ipmi_timestamp_fmt(stamp, "S+ %H:%M:%S"); } /* * IPMI_TIME_INIT_DONE is over 17 years. This should never * happen normally, but we'll support this anyway. */ else { - format = "S+ %y/%j %H:%M:%S"; + return ipmi_timestamp_fmt(stamp, "S+ %y/%j %H:%M:%S"); } } - return ipmi_timestamp_fmt(stamp, format); + return ipmi_timestamp_fmt(stamp, "%x %X %Z"); } char * ipmi_timestamp_date(uint32_t stamp) { - const char *format = "%x"; if (!ipmi_timestamp_is_valid(stamp)) { return "Unspecified"; } if (ipmi_timestamp_is_special(stamp)) { - format = "S+ %y/%j"; + return ipmi_timestamp_fmt(stamp, "S+ %y/%j"); } - return ipmi_timestamp_fmt(stamp, format); + return ipmi_timestamp_fmt(stamp, "%x"); } char * |