diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index c551fde7d1..fbfabaf24f 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -79,9 +79,9 @@ enum { ISIS_UI_LEVEL_BRIEF, #include "lib/log.h" void log_multiline(int priority, const char *prefix, const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); + PRINTFRR(3, 4); struct vty; void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); + PRINTFRR(3, 4); void vty_out_timestr(struct vty *vty, time_t uptime); #endif diff --git a/lib/compiler.h b/lib/compiler.h index 9ce91e3361..218100417c 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -218,6 +218,68 @@ extern "C" { #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) +/* sigh. this is so ugly, it overflows and wraps to being nice again. + * + * printfrr() supports "%Ld" for , whatever that is typedef'd to. + * However, gcc & clang think that "%Ld" is , which doesn't quite + * match up since int64_t is on a lot of 64-bit systems. + * + * If we have _FRR_ATTRIBUTE_PRINTFRR, we loaded a compiler plugin that + * replaces the whole format checking bits with a custom version that + * understands "%Ld" (along with "%pI4" and co.), so we don't need to do + * anything. + * + * If we don't have that attribute... we still want -Wformat to work. So, + * this is the "f*ck it" approach and we just redefine int64_t to always be + * . This should work until such a time that is + * something else (e.g. 128-bit integer)... let's just guard against that + * with the _Static_assert below and work with the world we have right now, + * where is always 64-bit. + */ + +/* these need to be included before any of the following, so we can + * "overwrite" things. + */ +#include +#include + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#define PRINTFRR(a, b) __attribute__((printfrr(a, b))) + +#else /* !_FRR_ATTRIBUTE_PRINTFRR */ +#define PRINTFRR(a, b) __attribute__((format(printf, a, b))) + +/* these should be typedefs, but might also be #define */ +#ifdef uint64_t +#undef uint64_t +#endif +#ifdef int64_t +#undef int64_t +#endif + +/* can't overwrite the typedef, but we can replace int64_t with _int64_t */ +typedef unsigned long long _uint64_t; +#define uint64_t _uint64_t +typedef signed long long _int64_t; +#define int64_t _int64_t + +/* if this breaks, 128-bit machines may have entered reality (or + * is something weird) + */ +#if __STDC_VERSION__ >= 201112L +_Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8, + "nobody expects the spanish intquisition"); +#endif + +/* since we redefined int64_t, we also need to redefine PRI*64 */ +#undef PRIu64 +#undef PRId64 +#undef PRIx64 +#define PRIu64 "llu" +#define PRId64 "lld" +#define PRIx64 "llx" +#endif /* !_FRR_ATTRIBUTE_PRINTFRR */ + #ifdef __cplusplus } #endif diff --git a/lib/log.h b/lib/log.h index 3ef4d2f379..c5ae6fe32f 100644 --- a/lib/log.h +++ b/lib/log.h @@ -81,20 +81,13 @@ extern void openzlog(const char *progname, const char *protoname, /* Close zlog function. */ extern void closezlog(void); -/* GCC have printf type attribute check. */ -#ifdef __GNUC__ -#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) -#else -#define PRINTF_ATTRIBUTE(a,b) -#endif /* __GNUC__ */ - /* Handy zlog functions. */ -extern void zlog_err(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); -extern void zlog_warn(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); -extern void zlog_info(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); -extern void zlog_notice(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); -extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); -extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); +extern void zlog_err(const char *format, ...) PRINTFRR(1, 2); +extern void zlog_warn(const char *format, ...) PRINTFRR(1, 2); +extern void zlog_info(const char *format, ...) PRINTFRR(1, 2); +extern void zlog_notice(const char *format, ...) PRINTFRR(1, 2); +extern void zlog_debug(const char *format, ...) PRINTFRR(1, 2); +extern void zlog(int priority, const char *format, ...) PRINTFRR(2, 3); /* For logs which have error codes associated with them */ #define flog_err(ferr_id, format, ...) \ diff --git a/lib/sbuf.h b/lib/sbuf.h index b1518a3aa8..9f0311006d 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -78,7 +78,7 @@ const char *sbuf_buf(struct sbuf *buf); void sbuf_free(struct sbuf *buf); #include "lib/log.h" void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); + PRINTFRR(3, 4); #ifdef __cplusplus } diff --git a/lib/termtable.h b/lib/termtable.h index 491010a856..4f7c595ce2 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -137,8 +137,7 @@ void ttable_cell_del(struct ttable_cell *cell); * columns were specified */ struct ttable_cell *ttable_insert_row(struct ttable *tt, unsigned int row, - const char *format, ...) - PRINTF_ATTRIBUTE(3, 4); + const char *format, ...) PRINTFRR(3, 4); /** * Inserts a new row at the end of the table. * @@ -164,7 +163,7 @@ struct ttable_cell *ttable_insert_row(struct ttable *tt, unsigned int row, * columns were specified */ struct ttable_cell *ttable_add_row(struct ttable *tt, const char *format, ...) - PRINTF_ATTRIBUTE(2, 3); + PRINTFRR(2, 3); /** * Removes a row from the table. diff --git a/lib/vty.h b/lib/vty.h index 035e758024..c7352efbd3 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -302,8 +302,8 @@ extern struct vty *vty_stdio(void (*atclose)(int isexit)); * - vty_endframe() clears the buffer without printing it, and prints an * extra string if the buffer was empty before (for context-end markers) */ -extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); -extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +extern int vty_out(struct vty *, const char *, ...) PRINTFRR(2, 3); +extern void vty_frame(struct vty *, const char *, ...) PRINTFRR(2, 3); extern void vty_endframe(struct vty *, const char *); bool vty_set_include(struct vty *vty, const char *regexp); diff --git a/lib/zebra.h b/lib/zebra.h index 2f9ada09be..51b4849f59 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -244,13 +244,6 @@ size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t destsize); #endif -/* GCC have printf type attribute check. */ -#ifdef __GNUC__ -#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) -#else -#define PRINTF_ATTRIBUTE(a,b) -#endif /* __GNUC__ */ - /* * RFC 3542 defines several macros for using struct cmsghdr. * Here, we define those that are not present diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index c8ef150b07..24de3fa88d 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -27,6 +27,7 @@ static int errors; +static void printcmp(const char *fmt, ...) PRINTFRR(1, 2); static void printcmp(const char *fmt, ...) { va_list ap; @@ -58,6 +59,7 @@ static void printcmp(const char *fmt, ...) errors++; } +static void printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); static void printchk(const char *ref, const char *fmt, ...) { va_list ap;