From a9a9dceab502498eb0afd368a06f1093f092bd0c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 28 Jul 2023 11:05:30 +0200 Subject: style: format "include/netlink-private/utils.h" with clang-format --- include/netlink-private/nl-auto.h | 2 +- include/netlink-private/utils.h | 242 +++++++++++++++++++------------------- tools/clang-format.sh | 1 - 3 files changed, 123 insertions(+), 122 deletions(-) diff --git a/include/netlink-private/nl-auto.h b/include/netlink-private/nl-auto.h index 4092782..4895169 100644 --- a/include/netlink-private/nl-auto.h +++ b/include/netlink-private/nl-auto.h @@ -5,7 +5,7 @@ #include -#define _nl_auto(fcn) __attribute__ ((__cleanup__(fcn))) +#define _nl_auto(fcn) __attribute__((__cleanup__(fcn))) #define _NL_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \ static inline void name(void *v) \ diff --git a/include/netlink-private/utils.h b/include/netlink-private/utils.h index 93a04c9..49a298b 100644 --- a/include/netlink-private/utils.h +++ b/include/netlink-private/utils.h @@ -24,15 +24,17 @@ /*****************************************************************************/ -#define _NL_STRINGIFY_ARG(contents) #contents -#define _NL_STRINGIFY(macro_or_string) _NL_STRINGIFY_ARG (macro_or_string) +#define _NL_STRINGIFY_ARG(contents) #contents +#define _NL_STRINGIFY(macro_or_string) _NL_STRINGIFY_ARG(macro_or_string) /*****************************************************************************/ -#if defined (__GNUC__) -#define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(GCC diagnostic ignored warning) -#elif defined (__clang__) -#define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(clang diagnostic ignored warning) +#if defined(__GNUC__) +#define _NL_PRAGMA_WARNING_DO(warning) \ + _NL_STRINGIFY(GCC diagnostic ignored warning) +#elif defined(__clang__) +#define _NL_PRAGMA_WARNING_DO(warning) \ + _NL_STRINGIFY(clang diagnostic ignored warning) #endif /* you can only suppress a specific warning that the compiler @@ -41,34 +43,34 @@ * It's not that bad however, because gcc and clang often have the * same name for the same warning. */ -#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define _NL_PRAGMA_WARNING_DISABLE(warning) \ - _Pragma("GCC diagnostic push") \ - _Pragma(_NL_PRAGMA_WARNING_DO("-Wpragmas")) \ - _Pragma(_NL_PRAGMA_WARNING_DO(warning)) -#elif defined (__clang__) -#define _NL_PRAGMA_WARNING_DISABLE(warning) \ - _Pragma("clang diagnostic push") \ - _Pragma(_NL_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \ - _Pragma(_NL_PRAGMA_WARNING_DO(warning)) +#if defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define _NL_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("GCC diagnostic push") \ + _Pragma(_NL_PRAGMA_WARNING_DO("-Wpragmas")) \ + _Pragma(_NL_PRAGMA_WARNING_DO(warning)) +#elif defined(__clang__) +#define _NL_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("clang diagnostic push") \ + _Pragma(_NL_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \ + _Pragma(_NL_PRAGMA_WARNING_DO(warning)) #else #define _NL_PRAGMA_WARNING_DISABLE(warning) #endif -#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define _NL_PRAGMA_WARNING_REENABLE \ - _Pragma("GCC diagnostic pop") -#elif defined (__clang__) -#define _NL_PRAGMA_WARNING_REENABLE \ - _Pragma("clang diagnostic pop") +#if defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define _NL_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop") +#elif defined(__clang__) +#define _NL_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop") #else #define _NL_PRAGMA_WARNING_REENABLE #endif /*****************************************************************************/ -#define _nl_unused __attribute__ ((__unused__)) -#define _nl_auto(fcn) __attribute__ ((__cleanup__(fcn))) +#define _nl_unused __attribute__((__unused__)) +#define _nl_auto(fcn) __attribute__((__cleanup__(fcn))) /*****************************************************************************/ @@ -89,14 +91,19 @@ /*****************************************************************************/ -#define _NL_STATIC_ASSERT(cond) ((void) sizeof (char[(cond) ? 1 : -1])) +#define _NL_STATIC_ASSERT(cond) ((void)sizeof(char[(cond) ? 1 : -1])) /*****************************************************************************/ #if defined(NL_MORE_ASSERTS) && NL_MORE_ASSERTS > 0 #define _nl_assert(cond) assert(cond) #else -#define _nl_assert(cond) do { if (0) { assert(cond); } } while (0) +#define _nl_assert(cond) \ + do { \ + if (0) { \ + assert(cond); \ + } \ + } while (0) #endif #define _nl_assert_not_reached() assert(0) @@ -148,63 +155,62 @@ extern const char *nl_strerror_l(int err); /* internal macro to calculate the size of a struct @type up to (and including) @field. * this will be used for .minlen policy fields, so that we require only a field of up * to the given size. */ -#define _nl_offsetofend(type, field) (offsetof (type, field) + sizeof (((type *) NULL)->field)) +#define _nl_offsetofend(type, field) \ + (offsetof(type, field) + sizeof(((type *)NULL)->field)) /*****************************************************************************/ -#define _nl_clear_pointer(pp, destroy) \ - ({ \ - __typeof__ (*(pp)) *_pp = (pp); \ - __typeof__ (*_pp) _p; \ - int _changed = 0; \ - \ - if ( _pp \ - && (_p = *_pp)) { \ +#define _nl_clear_pointer(pp, destroy) \ + ({ \ + __typeof__(*(pp)) *_pp = (pp); \ + __typeof__(*_pp) _p; \ + int _changed = 0; \ + \ + if (_pp && (_p = *_pp)) { \ _nl_unused const void *const _p_check_is_pointer = _p; \ - \ - *_pp = NULL; \ - \ - (destroy) (_p); \ - \ - _changed = 1; \ - } \ - _changed; \ + \ + *_pp = NULL; \ + \ + (destroy)(_p); \ + \ + _changed = 1; \ + } \ + _changed; \ }) -#define _nl_clear_free(pp) _nl_clear_pointer (pp, free) - -#define _nl_steal_pointer(pp) \ - ({ \ - __typeof__ (*(pp)) *const _pp = (pp); \ - __typeof__ (*_pp) _p = NULL; \ - \ - if ( _pp \ - && (_p = *_pp)) { \ - *_pp = NULL; \ - } \ - \ - _p; \ +#define _nl_clear_free(pp) _nl_clear_pointer(pp, free) + +#define _nl_steal_pointer(pp) \ + ({ \ + __typeof__(*(pp)) *const _pp = (pp); \ + __typeof__(*_pp) _p = NULL; \ + \ + if (_pp && (_p = *_pp)) { \ + *_pp = NULL; \ + } \ + \ + _p; \ }) /*****************************************************************************/ -#define _nl_malloc_maybe_a(alloca_maxlen, bytes, to_free) \ - ({ \ - const size_t _bytes = (bytes); \ - __typeof__ (to_free) _to_free = (to_free); \ - __typeof__ (*_to_free) _ptr; \ - \ - _NL_STATIC_ASSERT ((alloca_maxlen) <= 500); \ - _nl_assert (_to_free && !*_to_free); \ - \ - if (_bytes <= (alloca_maxlen)) { \ - _ptr = alloca (_bytes); \ - } else { \ - _ptr = malloc (_bytes); \ - *_to_free = _ptr; \ - }; \ - \ - _ptr; \ +#define _nl_malloc_maybe_a(alloca_maxlen, bytes, to_free) \ + ({ \ + const size_t _bytes = (bytes); \ + __typeof__(to_free) _to_free = (to_free); \ + __typeof__(*_to_free) _ptr; \ + \ + _NL_STATIC_ASSERT((alloca_maxlen) <= 500); \ + _nl_assert(_to_free && !*_to_free); \ + \ + if (_bytes <= (alloca_maxlen)) { \ + _ptr = alloca(_bytes); \ + } else { \ + _ptr = malloc(_bytes); \ + *_to_free = _ptr; \ + }; \ + \ + _ptr; \ }) /*****************************************************************************/ @@ -219,8 +225,7 @@ static inline bool _nl_streq0(const char *a, const char *b) return a == b || (a && b && _nl_streq(a, b)); } -static inline char * -_nl_strncpy_trunc(char *dst, const char *src, size_t len) +static inline char *_nl_strncpy_trunc(char *dst, const char *src, size_t len) { /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL * behavior of strncpy(). This is just strncpy() with gracefully handling truncation @@ -229,8 +234,8 @@ _nl_strncpy_trunc(char *dst, const char *src, size_t len) * Note that truncation is silently accepted. */ - _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation"); - _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow"); + _NL_PRAGMA_WARNING_DISABLE("-Wstringop-truncation"); + _NL_PRAGMA_WARNING_DISABLE("-Wstringop-overflow"); if (len > 0) { _nl_assert(dst); @@ -247,8 +252,7 @@ _nl_strncpy_trunc(char *dst, const char *src, size_t len) return dst; } -static inline char * -_nl_strncpy_assert(char *dst, const char *src, size_t len) +static inline char *_nl_strncpy_assert(char *dst, const char *src, size_t len) { /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL * behavior of strncpy(). This is just strncpy() with assertion against truncation @@ -258,8 +262,8 @@ _nl_strncpy_assert(char *dst, const char *src, size_t len) * against that. */ - _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation"); - _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow"); + _NL_PRAGMA_WARNING_DISABLE("-Wstringop-truncation"); + _NL_PRAGMA_WARNING_DISABLE("-Wstringop-overflow"); if (len > 0) { _nl_assert(dst); @@ -267,7 +271,7 @@ _nl_strncpy_assert(char *dst, const char *src, size_t len) strncpy(dst, src, len); - _nl_assert (dst[len - 1] == '\0'); + _nl_assert(dst[len - 1] == '\0'); dst[len - 1] = '\0'; } @@ -280,51 +284,50 @@ _nl_strncpy_assert(char *dst, const char *src, size_t len) #include "nl-auto.h" -#define _NL_RETURN_ON_ERR(cmd) \ - do { \ - int _err; \ - \ - _err = (cmd); \ - if (_err < 0) \ - return _err; \ +#define _NL_RETURN_ON_ERR(cmd) \ + do { \ + int _err; \ + \ + _err = (cmd); \ + if (_err < 0) \ + return _err; \ } while (0) -#define _NL_RETURN_E_ON_ERR(e, cmd) \ - do { \ - int _err; \ - \ - _err = (cmd); \ - if (_err < 0) { \ - _NL_STATIC_ASSERT((e) > 0); \ - return -(e); \ - } \ +#define _NL_RETURN_E_ON_ERR(e, cmd) \ + do { \ + int _err; \ + \ + _err = (cmd); \ + if (_err < 0) { \ + _NL_STATIC_ASSERT((e) > 0); \ + return -(e); \ + } \ } while (0) /* _NL_RETURN_ON_PUT_ERR() shall only be used with a put command (nla_put or nlmsg_append). * These commands can either fail with a regular error code (which gets propagated) * or with -NLE_NOMEM. However, they don't really try to allocate memory, so we don't * want to propagate -NLE_NOMEM. Instead, we coerce such failure to -NLE_MSGSIZE. */ -#define _NL_RETURN_ON_PUT_ERR(put_cmd) \ - do { \ - int _err; \ - \ - _err = (put_cmd); \ - if (_err < 0) { \ - if (_err == -NLE_NOMEM) { \ +#define _NL_RETURN_ON_PUT_ERR(put_cmd) \ + do { \ + int _err; \ + \ + _err = (put_cmd); \ + if (_err < 0) { \ + if (_err == -NLE_NOMEM) { \ /* nla_put() returns -NLE_NOMEM in case of out of buffer size. We don't * want to propagate that error and map it to -NLE_MSGSIZE. */ \ - return -NLE_MSGSIZE; \ - } \ + return -NLE_MSGSIZE; \ + } \ /* any other error can only be due to invalid parameters. Propagate the - * error, however also assert that it cannot be reached. */ \ - _nl_assert_not_reached (); \ - return _err; \ - } else \ - _nl_assert (_err == 0); \ + * error, however also assert that it cannot be reached. */ \ + _nl_assert_not_reached(); \ + return _err; \ + } else \ + _nl_assert(_err == 0); \ } while (0) -static inline int -_nl_close(int fd) +static inline int _nl_close(int fd) { int r; @@ -333,8 +336,7 @@ _nl_close(int fd) return r; } -static inline void * -_nl_memdup(const void *ptr, size_t len) +static inline void *_nl_memdup(const void *ptr, size_t len) { void *p; @@ -351,7 +353,7 @@ _nl_memdup(const void *ptr, size_t len) return p; } -#define _nl_memdup_ptr(ptr) ((__typeof__(ptr)) _nl_memdup((ptr), sizeof(*(ptr)))) +#define _nl_memdup_ptr(ptr) ((__typeof__(ptr))_nl_memdup((ptr), sizeof(*(ptr)))) /*****************************************************************************/ @@ -374,10 +376,10 @@ static inline char *_nl_inet_ntop(int addr_family, const void *addr, r = (char *)inet_ntop(addr_family, addr, buf, (addr_family == AF_INET) ? INET_ADDRSTRLEN : - INET6_ADDRSTRLEN); + INET6_ADDRSTRLEN); _nl_assert(r == buf); _nl_assert(strlen(r) < ((addr_family == AF_INET) ? INET_ADDRSTRLEN : - INET6_ADDRSTRLEN)); + INET6_ADDRSTRLEN)); return r; } @@ -387,7 +389,7 @@ static inline char *_nl_inet_ntop_dup(int addr_family, const void *addr) return (char *)_nl_inet_ntop(addr_family, addr, malloc((addr_family == AF_INET) ? INET_ADDRSTRLEN : - INET6_ADDRSTRLEN)); + INET6_ADDRSTRLEN)); } #endif diff --git a/tools/clang-format.sh b/tools/clang-format.sh index f430114..7c0c012 100755 --- a/tools/clang-format.sh +++ b/tools/clang-format.sh @@ -27,7 +27,6 @@ EXCLUDE_PATHS_TOPLEVEL+=( "include/netlink-private/socket.h" "include/netlink-private/tc.h" "include/netlink-private/types.h" - "include/netlink-private/utils.h" "include/netlink/addr.h" "include/netlink/attr.h" "include/netlink/cache-api.h" -- cgit v0.12 From 57c451fa3f804514b0f97765c2dfdbb58e867df4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 28 Jul 2023 11:03:23 +0200 Subject: utils: add various helpers to "include/netlink-private/utils.h" These are taken from NetworkManager code and renamed. The original code is LGPL-2.1-or-later licensed, so we are good. --- include/netlink-private/utils.h | 310 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 299 insertions(+), 11 deletions(-) diff --git a/include/netlink-private/utils.h b/include/netlink-private/utils.h index 49a298b..298cac3 100644 --- a/include/netlink-private/utils.h +++ b/include/netlink-private/utils.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -69,8 +70,20 @@ /*****************************************************************************/ +#define _nl_packed __attribute__((__packed__)) #define _nl_unused __attribute__((__unused__)) -#define _nl_auto(fcn) __attribute__((__cleanup__(fcn))) +#define _nl_always_inline __attribute__((__always_inline__)) +#define _nl_used __attribute__((__used__)) +#define _nl_pure __attribute__((__pure__)) +#define _nl_const __attribute__((__const__)) +#define _nl_noreturn __attribute__((__noreturn__)) +#define _nl_warn_unused_result __attribute__((__warn_unused_result__)) +#define _nl_printf(a, b) __attribute__((__format__(__printf__, a, b))) +#define _nl_align(s) __attribute__((__aligned__(s))) +#define _nl_section(s) __attribute__((__section__(s))) +#define _nl_alignof(type) __alignof(type) +#define _nl_alignas(type) _nl_align(_nl_alignof(type)) +#define _nl_deprecated(msg) __attribute__((__deprecated__(msg))) /*****************************************************************************/ @@ -110,6 +123,21 @@ /*****************************************************************************/ +#define _NL_BIT(n) (1ull << (n)) + +/*****************************************************************************/ + +#define _NL_PASTE_ARGS(identifier1, identifier2) identifier1##identifier2 +#define _NL_PASTE(identifier1, identifier2) \ + _NL_PASTE_ARGS(identifier1, identifier2) + +/* Taken from systemd's UNIQ_T and UNIQ macros. */ + +#define _NL_UNIQ_T(x, uniq) _NL_PASTE(__unique_prefix_, _NL_PASTE(x, uniq)) +#define _NL_UNIQ __COUNTER__ + +/*****************************************************************************/ + #define _nl_assert_addr_family_or_unspec(addr_family) \ do { \ typeof(addr_family) _addr_family = (addr_family); \ @@ -152,6 +180,276 @@ extern const char *nl_strerror_l(int err); /*****************************************************************************/ +static inline uintptr_t _nl_ptr_to_uintptr(const void *p) +{ + /* in C, pointers can only be compared (with less-than or greater-than) under certain + * circumstances. Since uintptr_t is supposed to be able to represent the pointer + * as a plain integer and also support to convert the integer back to the pointer, + * it should be safer to compare the pointers directly. + * + * Of course, this function isn't very useful beyond that its use makes it clear + * that we want to compare pointers by value, which otherwise may not be valid. */ + return (uintptr_t)p; +} + +/*****************************************************************************/ + +static inline int _nl_strcmp0(const char *s1, const char *s2) +{ + int c; + + /* like g_strcmp0(), but this is inlinable. + * + * Also, it is guaranteed to return either -1, 0, or 1. */ + if (s1 == s2) + return 0; + if (!s1) + return -1; + if (!s2) + return 1; + c = strcmp(s1, s2); + if (c < 0) + return -1; + if (c > 0) + return 1; + return 0; +} + +static inline bool _nl_streq(const char *a, const char *b) +{ + return !strcmp(a, b); +} + +static inline bool _nl_streq0(const char *a, const char *b) +{ + return a == b || (a && b && _nl_streq(a, b)); +} + +static inline int _nl_memcmp(const void *s1, const void *s2, size_t n) +{ + /* Workaround undefined behavior in memcmp() with NULL pointers. */ + if (n == 0) + return 0; + _nl_assert(s1); + _nl_assert(s2); + return memcmp(s1, s2, n); +} + +static inline bool _nl_memeq(const void *s1, const void *s2, size_t len) +{ + return _nl_memcmp(s1, s2, len) == 0; +} + +static inline void *_nl_memcpy(void *restrict dest, const void *restrict src, + size_t n) +{ + /* Workaround undefined behavior in memcpy() with NULL pointers. */ + if (n == 0) + return dest; + + _nl_assert(src); + return memcpy(dest, src, n); +} + +/*****************************************************************************/ + +#define _NL_INT_IS_SIGNED(arg) (!(((typeof(arg))-1) > 0)) + +#define _NL_INT_SAME_SIGNEDNESS(arg1, arg2) \ + (_NL_INT_IS_SIGNED(arg1) == _NL_INT_IS_SIGNED(arg2)) + +/*****************************************************************************/ + +/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate + * the argument possibly twice. + * + * Taken from systemd's MIN()/MAX() macros. */ + +#define _NL_MIN(a, b) __NL_MIN(_NL_UNIQ, a, _NL_UNIQ, b) +#define __NL_MIN(aq, a, bq, b) \ + ({ \ + typeof(a) _NL_UNIQ_T(A, aq) = (a); \ + typeof(b) _NL_UNIQ_T(B, bq) = (b); \ + \ + _NL_STATIC_ASSERT(_NL_INT_SAME_SIGNEDNESS(_NL_UNIQ_T(A, aq), \ + _NL_UNIQ_T(B, bq))); \ + \ + ((_NL_UNIQ_T(A, aq) < _NL_UNIQ_T(B, bq)) ? _NL_UNIQ_T(A, aq) : \ + _NL_UNIQ_T(B, bq)); \ + }) + +#define _NL_MAX(a, b) __NL_MAX(_NL_UNIQ, a, _NL_UNIQ, b) +#define __NL_MAX(aq, a, bq, b) \ + ({ \ + typeof(a) _NL_UNIQ_T(A, aq) = (a); \ + typeof(b) _NL_UNIQ_T(B, bq) = (b); \ + \ + _NL_STATIC_ASSERT(_NL_INT_SAME_SIGNEDNESS(_NL_UNIQ_T(A, aq), \ + _NL_UNIQ_T(B, bq))); \ + \ + ((_NL_UNIQ_T(A, aq) > _NL_UNIQ_T(B, bq)) ? _NL_UNIQ_T(A, aq) : \ + _NL_UNIQ_T(B, bq)); \ + }) + +#define _NL_CLAMP(x, low, high) \ + __NL_CLAMP(_NL_UNIQ, x, _NL_UNIQ, low, _NL_UNIQ, high) +#define __NL_CLAMP(xq, x, lowq, low, highq, high) \ + ({ \ + typeof(x) _NL_UNIQ_T(X, xq) = (x); \ + typeof(low) _NL_UNIQ_T(LOW, lowq) = (low); \ + typeof(high) _NL_UNIQ_T(HIGH, highq) = (high); \ + \ + _NL_STATIC_ASSERT(_NL_INT_SAME_SIGNEDNESS( \ + _NL_UNIQ_T(X, xq), _NL_UNIQ_T(LOW, lowq))); \ + _NL_STATIC_ASSERT(_NL_INT_SAME_SIGNEDNESS( \ + _NL_UNIQ_T(X, xq), _NL_UNIQ_T(HIGH, highq))); \ + \ + ((_NL_UNIQ_T(X, xq) > _NL_UNIQ_T(HIGH, highq)) ? \ + _NL_UNIQ_T(HIGH, highq) : \ + (_NL_UNIQ_T(X, xq) < _NL_UNIQ_T(LOW, lowq)) ? \ + _NL_UNIQ_T(LOW, lowq) : \ + _NL_UNIQ_T(X, xq)); \ + }) + +#define _NL_MAX_WITH_CMP(cmp, a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + (((cmp(_a, _b)) >= 0) ? _a : _b); \ + }) + +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define _NL_CONST_MAX(_A, _B) \ + (__builtin_choose_expr( \ + (__builtin_constant_p(_A) && __builtin_constant_p(_B) && \ + __builtin_types_compatible_p(typeof(_A), typeof(_B))), \ + ((_A) > (_B)) ? (_A) : (_B), ((void)0))) + +/*****************************************************************************/ + +#define _NL_CMP_RETURN(c) \ + do { \ + const int _cc = (c); \ + \ + if (_cc) \ + return _cc < 0 ? -1 : 1; \ + } while (0) + +#define _NL_CMP_RETURN_DIRECT(c) \ + /* Usually we want that our CMP functions return strictly + * -1, 0, or 1. _NL_CMP_RETURN_DIRECT() is like _NL_CMP_RETURN(), + * except, it does not clamp the integer value. */ \ + do { \ + const int _cc = (c); \ + \ + if (_cc) \ + return _cc; \ + } while (0) + +#define _NL_CMP_SELF(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a == _b) \ + return 0; \ + if (!_a) \ + return -1; \ + if (!_b) \ + return 1; \ + } while (0) + +/*****************************************************************************/ + +#define _NL_CMP_DIRECT(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a != _b) \ + return (_a < _b) ? -1 : 1; \ + } while (0) + +#define _NL_CMP_DIRECT_UNSAFE(a, b) \ + /* This variant is "unsafe", because it evaluates the arguments more then once. + * This is only useful for bitfields, for which typeof() doesn't work. + * Don't use otherwise. */ \ + do { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ + } while (0) + +/* In the general case, direct pointer comparison is undefined behavior in C. + * Avoid that by casting pointers to void* and then to uintptr_t. This comparison + * is not really meaningful, except that it provides some kind of stable sort order + * between pointers (that can otherwise not be compared). */ +#define _NL_CMP_DIRECT_PTR(a, b) \ + _NL_CMP_DIRECT(_nl_ptr_to_uintptr(a), _nl_ptr_to_uintptr(b)) + +#define _NL_CMP_DIRECT_BOOL(a, b) _NL_CMP_DIRECT(!!(a), !!(b)) + +#define _NL_CMP_DIRECT_MEMCMP(a, b, size) \ + _NL_CMP_RETURN(_nl_memcmp((a), (b), (size))) + +#define _NL_CMP_DIRECT_STRCMP(a, b) _NL_CMP_RETURN_DIRECT(strcmp((a), (b))) + +#define _NL_CMP_DIRECT_STRCMP0(a, b) \ + _NL_CMP_RETURN_DIRECT(_nl_strcmp0((a), (b))) + +#define _NL_CMP_DIRECT_STR_INTERNED(a, b) \ + /* This is interned strings, which are first checked for equality only using pointer + * comparison. Only in case of differences, the sort order is still determined by strcmp(). */ \ + do { \ + const char *const _a = (a); \ + const char *const _b = (b); \ + \ + if (_a != _b) \ + _NL_CMP_RETURN_DIRECT(_nl_strcmp0(_a, _b)); \ + } while (0) + +#define _NL_CMP_DIRECT_IN6ADDR(a, b) \ + do { \ + const struct in6_addr *const _a = (a); \ + const struct in6_addr *const _b = (b); \ + \ + _NL_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ + } while (0) + +/*****************************************************************************/ + +#define _NL_CMP_FIELD(a, b, field) _NL_CMP_DIRECT(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_UNSAFE(a, b, field) \ + /* This variant is "unsafe", because it evaluates the arguments more then once. + * This is only useful for bitfields, for which typeof() doesn't work. + * Don't use otherwise. */ \ + _NL_CMP_DIRECT_UNSAFE(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_BOOL(a, b, field) \ + _NL_CMP_DIRECT_BOOL(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_STR(a, b, field) \ + _NL_CMP_DIRECT_STRCMP(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_STR0(a, b, field) \ + _NL_CMP_DIRECT_STRCMP0(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_STR_INTERNED(a, b, field) \ + _NL_CMP_DIRECT_STR_INTERNED(((a)->field), ((b)->field)) + +#define _NL_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \ + _NL_CMP_DIRECT_MEMCMP(&((a)->field), &((b)->field), \ + _NL_MIN(len, sizeof((a)->field))) + +#define _NL_CMP_FIELD_MEMCMP(a, b, field) \ + _NL_CMP_DIRECT_MEMCMP(&((a)->field), &((b)->field), sizeof((a)->field)) + +#define _NL_CMP_FIELD_IN6ADDR(a, b, field) \ + _NL_CMP_DIRECT_IN6ADDR(&((a)->field), &((b)->field)) + +/*****************************************************************************/ + /* internal macro to calculate the size of a struct @type up to (and including) @field. * this will be used for .minlen policy fields, so that we require only a field of up * to the given size. */ @@ -215,16 +513,6 @@ extern const char *nl_strerror_l(int err); /*****************************************************************************/ -static inline bool _nl_streq(const char *a, const char *b) -{ - return !strcmp(a, b); -} - -static inline bool _nl_streq0(const char *a, const char *b) -{ - return a == b || (a && b && _nl_streq(a, b)); -} - static inline char *_nl_strncpy_trunc(char *dst, const char *src, size_t len) { /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL -- cgit v0.12 From 2e0ae977e4d9172fda78dbf0b31b47bd59e7ae3e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 28 Jul 2023 11:23:22 +0200 Subject: all: use _NL_{MIN,MAX}() macros Replace the use of the previous min()/min_t()/max()/max_t(). - min_t()/max_t() required a type, and would do plain assignment, which C would not complain about. It is thus a cumbersome and not very safe pattern. Avoid it. - min()/max() did better, it used typeof() to preserve the argument types and automatically detect it. However, it also required that both arguments had the same integer type, which is unnecessarily strict. _NL_MIN()/_NL_MAX() does better. It accepts arguments of any integer types, but has a static assertions that they match in signedness. So it's more flexible to use than min()/max() and still quite safe. Prefer the new macros. --- lib/addr.c | 2 +- lib/attr.c | 2 +- lib/msg.c | 2 +- lib/route/cls/ematch_syntax.y | 2 +- lib/route/link/inet.c | 2 +- lib/route/link/inet6.c | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/addr.c b/lib/addr.c index d0b5f33..6ca3bae 100644 --- a/lib/addr.c +++ b/lib/addr.c @@ -625,7 +625,7 @@ int nl_addr_cmp_prefix(const struct nl_addr *a, const struct nl_addr *b) int d = a->a_family - b->a_family; if (d == 0) { - int len = min(a->a_prefixlen, b->a_prefixlen); + int len = _NL_MIN(a->a_prefixlen, b->a_prefixlen); int bytes = len / 8; d = memcmp(a->a_addr, b->a_addr, bytes); diff --git a/lib/attr.c b/lib/attr.c index a8913d3..d919811 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -350,7 +350,7 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count) if (!src) return 0; - minlen = min_t(int, count, nla_len(src)); + minlen = _NL_MIN(count, nla_len(src)); memcpy(dest, nla_data(src), minlen); return minlen; diff --git a/lib/msg.c b/lib/msg.c index 17ca812..0e64722 100644 --- a/lib/msg.c +++ b/lib/msg.c @@ -148,7 +148,7 @@ struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen) */ int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) { - return max_t(int, nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen), 0); + return _NL_MAX(nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen), 0u); } /** @} */ diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y index 0c89603..0832a6e 100644 --- a/lib/route/cls/ematch_syntax.y +++ b/lib/route/cls/ematch_syntax.y @@ -406,7 +406,7 @@ pattern: if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) { $$.len = nl_addr_get_len(addr); - $$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8); + $$.index = _NL_MIN($$.len, nl_addr_get_prefixlen(addr)/8); if (!($$.data = calloc(1, $$.len))) { nl_addr_put(addr); diff --git a/lib/route/link/inet.c b/lib/route/link/inet.c index 2f95fb6..b4a520a 100644 --- a/lib/route/link/inet.c +++ b/lib/route/link/inet.c @@ -104,7 +104,7 @@ static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data if (tb[IFLA_INET_CONF]) { int i; - int len = min_t(int, IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4); + int len = _NL_MIN(IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4); for (i = 0; i < len; i++) id->i_confset[i] = 1; diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c index 08b29a8..e8310b3 100644 --- a/lib/route/link/inet6.c +++ b/lib/route/link/inet6.c @@ -167,7 +167,7 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, sizeof(i6->i6_cacheinfo)); if (tb[IFLA_INET6_CONF]) { - i6->i6_conf_len = min(ARRAY_SIZE(i6->i6_conf), + i6->i6_conf_len = _NL_MIN(ARRAY_SIZE(i6->i6_conf), nla_len(tb[IFLA_INET6_CONF]) / sizeof(i6->i6_conf[0])); nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF], @@ -202,7 +202,7 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, map_stat_id = map_stat_id_from_IPSTATS_MIB_v1; } - len = min_t(int, __IPSTATS_MIB_MAX, len); + len = _NL_MIN(__IPSTATS_MIB_MAX, len); for (i = 1; i < len; i++) { memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat)); rtnl_link_set_stat(link, map_stat_id[i], stat); @@ -213,7 +213,7 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]); uint64_t stat; int i; - int len = min_t(int, __ICMP6_MIB_MAX, nla_len(tb[IFLA_INET6_ICMP6STATS]) / 8); + int len = _NL_MIN(__ICMP6_MIB_MAX, nla_len(tb[IFLA_INET6_ICMP6STATS]) / 8); _NL_STATIC_ASSERT (__ICMP6_MIB_MAX == 6); _NL_STATIC_ASSERT (RTNL_LINK_ICMP6_CSUMERRORS - RTNL_LINK_ICMP6_INMSGS + 1 == 5); -- cgit v0.12 From 859b89dc567a60007151037bb2eb0cccbfca1f8c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 28 Jul 2023 11:23:53 +0200 Subject: include: drop now unused min()/max()/min_t()/max_t() macros --- include/netlink-private/netlink.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/include/netlink-private/netlink.h b/include/netlink-private/netlink.h index d86a55d..3d0c216 100644 --- a/include/netlink-private/netlink.h +++ b/include/netlink-private/netlink.h @@ -153,23 +153,6 @@ static inline int nl_cb_call(struct nl_cb *cb, enum nl_cb_type type, struct nl_m #undef __deprecated #define __deprecated __attribute__ ((deprecated)) -#define min(x,y) ({ \ - __typeof__(x) _x = (x); \ - __typeof__(y) _y = (y); \ - (void) (&_x == &_y); \ - _x < _y ? _x : _y; }) - -#define max(x,y) ({ \ - __typeof__(x) _x = (x); \ - __typeof__(y) _y = (y); \ - (void) (&_x == &_y); \ - _x > _y ? _x : _y; }) - -#define min_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) -#define max_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) - extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *, struct nlmsghdr *, struct nl_parser_param *); -- cgit v0.12 From ca34ad524ec7a9f0e24bb5975b178a3e70268f0f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 28 Jul 2023 11:24:26 +0200 Subject: lib: handle negative and zero size in nla_memcpy() a negative count is a bug in the caller. Still, handle it better than just crashing. Maybe we should assert, but it doesn't seem best to assert against user input. Also, if count is zero, don't call memcpy(). Calling memcpy() requires that the source and destination pointers are valid, otherwise it's undefined behavior. I think if the caller tells us to copy zero bytes, we should never look at the destination pointer. --- lib/attr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/attr.c b/lib/attr.c index d919811..85a11e7 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -349,10 +349,13 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count) if (!src) return 0; - + minlen = _NL_MIN(count, nla_len(src)); - memcpy(dest, nla_data(src), minlen); + if (minlen <= 0) + return 0; + + memcpy(dest, nla_data(src), minlen); return minlen; } -- cgit v0.12