Commit graph

89 commits

Author SHA1 Message Date
Thomas Haller
4733cf7460
std-aux: add c_list_is_empty_or_single() helper
Having a list with only one element is often interesting to know. For
example, if you are about to unlink an element, you may want to check
whether afterwards the list is empty.

Add c_list_is_empty_or_single() for that. It is probably more efficient than
plain c_list_length_is(list, 1) and also a better name.
2023-03-08 15:34:47 +01:00
Thomas Haller
dc5ac4d83c
std-aux/trivial: add code comment to NM_IS_IPv4() 2023-03-08 15:34:46 +01:00
Thomas Haller
5973e83160
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1529
2023-02-13 15:33:02 +01:00
Thomas Haller
d3548279c1
std-aux: suppress verbose assert message with _nm_assert_fail()
We also do that with g_return*() macros. These strings increase the
binary size for little use. Drop them, unless we build with
more asserts enabled.

This affects nm_assert() messages.
2023-02-13 09:33:10 +01:00
Thomas Haller
a29eb970c8
Revert "std-aux: drop assertion and function name from assert() in release mode"
glibc defines __assert_fail as:

  extern void __assert_fail (const char *__assertion, const char *__file,
                             unsigned int __line, const char *__function)
       __THROW __attribute__ ((__noreturn__));

but musl as:

  _Noreturn void __assert_fail (const char *, const char *, int, const char *);

(note the difference in the type for the line argument).

This cannot be made to work, unless we would detect the used type at configure
time, which seems too much effort.

Drop this again.

This reverts commit 1ce29e120b.

Fixes: 1ce29e120b ('std-aux: drop assertion and function name from assert() in release mode')
2023-02-13 08:46:40 +01:00
Thomas Haller
a300809f3c
systemd: update code from upstream (2023-02-07)
This is a direct dump from systemd git.

  $ git clean -fdx && \
    git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \
    git add .

======

SYSTEMD_DIR=../systemd
COMMIT=9eba03c7b10fe98e0443508402b3f9804230453e

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files -z :/src/libnm-systemd-core/src/ \
                :/src/libnm-systemd-shared/src/ \
                :/src/libnm-std-aux/unaligned-fundamental.h \
                :/src/libnm-std-aux/unaligned.h | \
  xargs -0 rm -f

nm_copy_sd_shared() {
    mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1"
}

nm_copy_sd_core() {
    mkdir -p "./src/libnm-systemd-core/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1"
}

nm_copy_sd_stdaux() {
    mkdir -p "./src/libnm-std-aux/"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}"
}

nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd_core "src/libsystemd-network/network-common.c"
nm_copy_sd_core "src/libsystemd-network/network-common.h"
nm_copy_sd_core "src/libsystemd-network/network-internal.h"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd_core "src/libsystemd/sd-device/device-util.h"
nm_copy_sd_core "src/libsystemd/sd-event/event-source.h"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.h"
nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd_core "src/systemd/_sd-common.h"
nm_copy_sd_core "src/systemd/sd-device.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-option.h"
nm_copy_sd_core "src/systemd/sd-event.h"
nm_copy_sd_core "src/systemd/sd-id128.h"
nm_copy_sd_core "src/systemd/sd-ndisc.h"
nm_copy_sd_shared "src/basic/alloc-util.c"
nm_copy_sd_shared "src/basic/alloc-util.h"
nm_copy_sd_shared "src/basic/async.h"
nm_copy_sd_shared "src/basic/cgroup-util.h"
nm_copy_sd_shared "src/basic/constants.h"
nm_copy_sd_shared "src/basic/dns-def.h"
nm_copy_sd_shared "src/basic/env-file.c"
nm_copy_sd_shared "src/basic/env-file.h"
nm_copy_sd_shared "src/basic/env-util.c"
nm_copy_sd_shared "src/basic/env-util.h"
nm_copy_sd_shared "src/basic/errno-util.h"
nm_copy_sd_shared "src/basic/escape.c"
nm_copy_sd_shared "src/basic/escape.h"
nm_copy_sd_shared "src/basic/ether-addr-util.c"
nm_copy_sd_shared "src/basic/ether-addr-util.h"
nm_copy_sd_shared "src/basic/extract-word.c"
nm_copy_sd_shared "src/basic/extract-word.h"
nm_copy_sd_shared "src/basic/fd-util.c"
nm_copy_sd_shared "src/basic/fd-util.h"
nm_copy_sd_shared "src/basic/fileio.c"
nm_copy_sd_shared "src/basic/fileio.h"
nm_copy_sd_shared "src/basic/format-util.c"
nm_copy_sd_shared "src/basic/format-util.h"
nm_copy_sd_shared "src/basic/fs-util.c"
nm_copy_sd_shared "src/basic/fs-util.h"
nm_copy_sd_shared "src/basic/glyph-util.c"
nm_copy_sd_shared "src/basic/glyph-util.h"
nm_copy_sd_shared "src/basic/hash-funcs.c"
nm_copy_sd_shared "src/basic/hash-funcs.h"
nm_copy_sd_shared "src/basic/hashmap.c"
nm_copy_sd_shared "src/basic/hashmap.h"
nm_copy_sd_shared "src/basic/hexdecoct.c"
nm_copy_sd_shared "src/basic/hexdecoct.h"
nm_copy_sd_shared "src/basic/hostname-util.c"
nm_copy_sd_shared "src/basic/hostname-util.h"
nm_copy_sd_shared "src/basic/in-addr-util.c"
nm_copy_sd_shared "src/basic/in-addr-util.h"
nm_copy_sd_shared "src/basic/inotify-util.c"
nm_copy_sd_shared "src/basic/inotify-util.h"
nm_copy_sd_shared "src/basic/io-util.c"
nm_copy_sd_shared "src/basic/io-util.h"
nm_copy_sd_shared "src/basic/list.h"
nm_copy_sd_shared "src/basic/locale-util.c"
nm_copy_sd_shared "src/basic/locale-util.h"
nm_copy_sd_shared "src/basic/log.h"
nm_copy_sd_shared "src/basic/logarithm.h"
nm_copy_sd_shared "src/basic/macro.h"
nm_copy_sd_shared "src/basic/memory-util.c"
nm_copy_sd_shared "src/basic/memory-util.h"
nm_copy_sd_shared "src/basic/mempool.c"
nm_copy_sd_shared "src/basic/mempool.h"
nm_copy_sd_shared "src/basic/missing_fcntl.h"
nm_copy_sd_shared "src/basic/missing_random.h"
nm_copy_sd_shared "src/basic/missing_socket.h"
nm_copy_sd_shared "src/basic/missing_stat.h"
nm_copy_sd_shared "src/basic/missing_syscall.h"
nm_copy_sd_shared "src/basic/missing_type.h"
nm_copy_sd_shared "src/basic/ordered-set.c"
nm_copy_sd_shared "src/basic/ordered-set.h"
nm_copy_sd_shared "src/basic/parse-util.c"
nm_copy_sd_shared "src/basic/parse-util.h"
nm_copy_sd_shared "src/basic/path-util.c"
nm_copy_sd_shared "src/basic/path-util.h"
nm_copy_sd_shared "src/basic/prioq.c"
nm_copy_sd_shared "src/basic/prioq.h"
nm_copy_sd_shared "src/basic/process-util.c"
nm_copy_sd_shared "src/basic/process-util.h"
nm_copy_sd_shared "src/basic/random-util.c"
nm_copy_sd_shared "src/basic/random-util.h"
nm_copy_sd_shared "src/basic/ratelimit.c"
nm_copy_sd_shared "src/basic/ratelimit.h"
nm_copy_sd_shared "src/basic/set.h"
nm_copy_sd_shared "src/basic/signal-util.c"
nm_copy_sd_shared "src/basic/signal-util.h"
nm_copy_sd_shared "src/basic/siphash24.h"
nm_copy_sd_shared "src/basic/socket-util.c"
nm_copy_sd_shared "src/basic/socket-util.h"
nm_copy_sd_shared "src/basic/sort-util.h"
nm_copy_sd_shared "src/basic/sparse-endian.h"
nm_copy_sd_shared "src/basic/stat-util.c"
nm_copy_sd_shared "src/basic/stat-util.h"
nm_copy_sd_shared "src/basic/stdio-util.h"
nm_copy_sd_shared "src/basic/string-table.c"
nm_copy_sd_shared "src/basic/string-table.h"
nm_copy_sd_shared "src/basic/string-util.c"
nm_copy_sd_shared "src/basic/string-util.h"
nm_copy_sd_shared "src/basic/strv.c"
nm_copy_sd_shared "src/basic/strv.h"
nm_copy_sd_shared "src/basic/strxcpyx.c"
nm_copy_sd_shared "src/basic/strxcpyx.h"
nm_copy_sd_shared "src/basic/time-util.c"
nm_copy_sd_shared "src/basic/time-util.h"
nm_copy_sd_shared "src/basic/tmpfile-util.c"
nm_copy_sd_shared "src/basic/tmpfile-util.h"
nm_copy_sd_shared "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/user-util.h"
nm_copy_sd_shared "src/basic/utf8.c"
nm_copy_sd_shared "src/basic/utf8.h"
nm_copy_sd_shared "src/fundamental/macro-fundamental.h"
nm_copy_sd_shared "src/fundamental/memory-util-fundamental.h"
nm_copy_sd_shared "src/fundamental/sha256.c"
nm_copy_sd_shared "src/fundamental/sha256.h"
nm_copy_sd_shared "src/fundamental/string-util-fundamental.c"
nm_copy_sd_shared "src/fundamental/string-util-fundamental.h"
nm_copy_sd_shared "src/shared/dns-domain.c"
nm_copy_sd_shared "src/shared/dns-domain.h"
nm_copy_sd_shared "src/shared/log-link.h"
nm_copy_sd_shared "src/shared/web-util.c"
nm_copy_sd_shared "src/shared/web-util.h"
nm_copy_sd_stdaux "src/basic/unaligned.h"
nm_copy_sd_stdaux "src/fundamental/unaligned-fundamental.h"
2023-02-08 18:59:33 +01:00
Thomas Haller
0b1177cb18
all: use _NM_G_TYPE_CHECK_INSTANCE_CAST() for internal uses
G_TYPE_CHECK_INSTANCE_CAST() can trigger a "-Wcast-align":

    src/core/devices/nm-device-macvlan.c: In function 'parent_changed_notify':
    /usr/include/glib-2.0/gobject/gtype.h:2421:42: error: cast increases required alignment of target type [-Werror=cast-align]
     2421 | #  define _G_TYPE_CIC(ip, gt, ct)       ((ct*) ip)
          |                                          ^
    /usr/include/glib-2.0/gobject/gtype.h:501:66: note: in expansion of macro '_G_TYPE_CIC'
      501 | #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type)    (_G_TYPE_CIC ((instance), (g_type), c_type))
          |                                                                  ^~~~~~~~~~~
    src/core/devices/nm-device-macvlan.h:13:6: note: in expansion of macro 'G_TYPE_CHECK_INSTANCE_CAST'
       13 |     (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan))
          |      ^~~~~~~~~~~~~~~~~~~~~~~~~~

Avoid that by using _NM_G_TYPE_CHECK_INSTANCE_CAST().

This can only be done for our internal usages. The public headers
of libnm are not changed.
2022-12-16 10:55:03 +01:00
Thomas Haller
2b89b2dc01
std-aux: add _NM_PTR_IS_ALIGNED() helper macro 2022-12-16 10:53:23 +01:00
Thomas Haller
63b34ac78a
std-aux: allow nesting of NM_CAST_ALIGN() macros
To support:

    return NM_CAST_ALIGN(const NMPObject,
                         nm_dedup_multi_obj_ref(NM_CAST_ALIGN(const NMDedupMultiObj, obj)));
2022-12-14 09:40:02 +01:00
Thomas Haller
4ecd25a139
std-aux: add NM_CAST_ALIGN() helper 2022-12-09 09:15:55 +01:00
Thomas Haller
4753358dd5
std-aux: mark failures of nm_assert() as unreachable code
- with nm_assert(), if the argument is a compile time constant
  always check it (regardless of NDEBUG, G_DISABLE_ASSERT)
  and mark the failure as _nm_unreachable_code(). We do this,
  even if we usually would not evaluate run time checks with
  NDEBUG/G_DISABLE_ASSERT.

- with nm_assert_se(), if assertions are disabled with NDEBUG
  and G_DISABLE_ASSERT, still mark the path as _nm_unreachable_code().
2022-12-06 17:03:04 +01:00
Thomas Haller
06931221b5
std-aux: mark _nm_assert_fail() as _nm_unreachable_code() with NDEBUG/G_DISABLE_ASSERT
This is useful, because it can avoid compiler warnings that are
emitted if the compiler things that the code can be reached.
_nm_assert_fail() can clearly never be reached (unless a bug happens).

When compiling we can disable assertion checks with
NDEBUG/G_DISABLE_ASSERT, but if we know that an assertion must not be
hit (for example with nm_assert_not_reached()) then we still want to
mark the path as unreachable, even if assert() does not abort the
process.
2022-12-06 17:03:04 +01:00
Thomas Haller
5ac5d7f8c3
std-aux: add _nm_unreachable_code() macro to wrap __builtin_unreachable()
This is a GCC-ism, but clang and all our current compiler support it.
2022-12-06 17:03:04 +01:00
Thomas Haller
fffdb14887
std-aux: make NM_BOOLEAN_EXPR() a constant expression for constant arguments
This allows the compiler to see that nm_assert(0) is unreachable code.
That is because nm_assert(0) calls NM_LIKELY(0), which calls
NM_BOOLEAN_EXPR(0). The latter was a statement expression, which
to the compiler was not a constant expression. Hence, this may trigger
compiler warnings about uninitialized variables.

Let NM_BOOLEAN_EXPR() to be constant, if the arguments are.

This can avoid compiler warnings in some cases.

Note that __builtin_choose_expr(__builtin_constant_p(...), ...) does
not properly work with gcc 4.8 ([1]). Hence only do macro shenanigans
with a newer gcc. Then entire point of NM_BOOLEAN_EXPR() is anyway
to preserve the "-Wparentheses" warning (while only evaluating the
argument once, being safe with nested invocations, propagate constness).
If we don't care about "-Wparentheses", it should be the same as
(!!(expr)). We can ignore that on non-recent gcc.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19449
2022-12-06 17:03:03 +01:00
Thomas Haller
7483dfd7c4
std-aux: fix _NM_ASSERT_FAIL_ENABLED for plain assert() and NDEBUG
Fixes: 8e3299498d ('std-aux,glib-aux: rework nm_assert() implementations')
2022-12-06 17:02:37 +01:00
Thomas Haller
18e107e098
std-aux: implement static-asserts via bitfields
The implementation for static asserts with (sizeof(char[(cond) ? 1 : -1]))
silently fails if the condition is not a compile time constant, because
it results in a VLA which is evaluated at runtime. Well, for that reason
we build with "-Wvla" to catch accidentally using a non-const expression
in a static assert. But still, we can do better. Use instead bitfields
to trigger the compiler error. This works only with static expressions
and also without "-Wvla".

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1468
2022-11-23 18:02:38 +01:00
Thomas Haller
e7b1fd9dbc
std-aux: add code comment to NM_BOOLEAN_EXPR() 2022-11-04 09:27:37 +01:00
Beniamino Galvani
8bd72d5f2e std-aux: fix NM_LIKELY()/NM_UNLIKELY() macros
Fix this compile error when "defined(__GNUC__) && (__GNUC__ > 2) &&
defined(__OPTIMIZE__)" doesn't match:

  In file included from ../src/libnm-std-aux/nm-default-std.h:102,
                   from ../src/libnm-std-aux/nm-std-utils.c:3:
  ../src/libnm-std-aux/nm-std-aux.h: In function ‘NM_ALIGN_TO’:
  ../src/libnm-std-aux/nm-std-aux.h:160:6: error: expected expression before ‘{’ token
    160 |     ({                                 \
        |      ^
  ../src/libnm-std-aux/nm-std-aux.h:169:31: note: in expansion of macro ‘_NM_BOOLEAN_EXPR_IMPL’
    169 | #define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL(NM_UNIQ, expr)
        |                               ^~~~~~~~~~~~~~~~~~~~~
  ../src/libnm-std-aux/nm-std-aux.h:175:27: note: in expansion of macro ‘NM_BOOLEAN_EXPR’
    175 | #define NM_LIKELY(expr)   NM_BOOLEAN_EXPR(expr)
        |                           ^~~~~~~~~~~~~~~
  ../src/libnm-std-aux/nm-std-aux.h:238:19: note: in expansion of macro ‘NM_LIKELY’
    238 |         } else if NM_LIKELY (cond) {                                  \
        |                   ^~~~~~~~~
  ../src/libnm-std-aux/nm-std-aux.h:449:5: note: in expansion of macro ‘nm_assert’
    449 |     nm_assert(nm_utils_is_power_of_two(ali));
        |     ^~~~~~~~~

The NM_LIKELY()/NM_UNLIKELY() macros should be alwas called enclosed
in parentheses like in:

 if (NM_LIKELY(i == 1)) ...

and should be expanded with only a single pair of parentheses so that
expressions like (i = 1) generate a compiler warning.

Fixes: 030d68aef7 ('shared: add nm_assert() to "nm-std-aux.h"')
2022-11-04 09:12:04 +01:00
Thomas Haller
0ffe391f82
std-aux: fix build error due to __assert_fail() missing with NDEBUG
<assert.h> only defines __assert_fail() if NDEBUG is not on.
Fix that.

Fixes: 8e3299498d ('std-aux,glib-aux: rework nm_assert() implementations')
2022-10-29 21:43:33 +02:00
Thomas Haller
3254f33b33
std-aux: assert against any EBADF error in nm_close()
Previously, nm_close() accepted EBADF, as long as fd was negative.

Getting EBADF for a non-negative file descriptor is a serious bug,
because in multi threaded applications there is a race to close
an unrelated file descriptor. Also, it indicates that somebody
messed up the tracking of the resource, which indicates a bug.

Getting EBADF on a negative FD is less of a problem.
But it still indicates that the caller does something they likely
don't intend to.

Assert against any EBADF.

Note that nm_clear_fd() and nm_auto_close take already care to not
close negative "file descriptors". So, if you use those, you are
not affected.

If you want a close function that doesn't care about whether fd is set,
then maybe use `nm_clear_fd(&fd)` instead.
2022-10-25 13:12:48 +02:00
Thomas Haller
ad7d5887cd
all: cleanup close() handling and clarify nm_close()/nm_close_with_error()
Cleanup the handling of close().

First of all, closing an invalid (non-negative) file descriptor (EBADF) is
always a serious bug. We want to catch that. Hence, we should use nm_close()
(or nm_close_with_error()) which asserts against such bugs. Don't ever use
close() directly, to get that additional assertion.

Also, our nm_close() handles EINTR internally and correctly. Recent
POSIX defines that on EINTR the close should be retried. On Linux,
that is never correct. After close() returns, the file descriptor is
always closed (or invalid). nm_close() gets this right, and pretends
that EINTR is a success (without retrying).

The majority of our file descriptors are sockets, etc. That means,
often an error from close isn't something that we want to handle. Adjust
nm_close() to return no error and preserve the caller's errno. That is
the appropriate reaction to error (ignoring it) in most of our cases.

And error from close may mean that there was an IO error (except EINTR
and EBADF). In a few cases, we may want to handle that. For those
cases we have nm_close_with_error().

TL;DR: use almost always nm_close(). Unless you want to handle the error
code, then use nm_close_with_error(). Never use close() directly.

There is much reading on the internet about handling errors of close and
in particular EINTR. See the following links:

https://lwn.net/Articles/576478/
https://askcodes.net/coding/what-to-do-if-a-posix-close-call-fails-
https://www.austingroupbugs.net/view.php?id=529
https://sourceware.org/bugzilla/show_bug.cgi?id=14627
https://news.ycombinator.com/item?id=3363819
https://peps.python.org/pep-0475/
2022-10-25 13:12:48 +02:00
Thomas Haller
1ce29e120b
std-aux: drop assertion and function name from assert() in release mode
For g_assert() and g_return*() we already do the same, in
"src/libnm-glib-aux/nm-gassert-patch.h"

Also patch __assert_fail() so that it omits the condition text and the
function name in production builds.

Note that this is a bit ugly, for two reasons:

- again, we make assumptions that __assert_fail() exists. In practice,
  this is the case for glibc and musl.

- <assert.h> can be included multiple times, while also forward
  declaring __assert_fail(). That means, we cannot add a macro

  #define __assert_fail(...)

  because that would break the forward declaration. Instead,
  just `#define __assert_fail _nm_assert_fail_internal`

Of course, this only affects direct calls to assert(), which we have
few. nm_assert() is not affected, because that anyway doesn't do
anything, unless NM_MORE_ASSERTS is enabled.
2022-10-25 13:12:48 +02:00
Thomas Haller
8e3299498d
std-aux,glib-aux: rework nm_assert() implementations
1) ensure the compiler always sees the condition (even if
  it's unreachable). That is important, to avoid warnings
  about unused variables and to ensure the condition compiles.
  Previously, if NM_MORE_ASSERTS was enabled and NDEBUG (or
  G_DISABLE_ASSERT) was defined, the condition was not seen by
  the compiler.

2) to achieve point 1, we evaluate the expression now always in
  nm_assert() macro directly. This also has the benefit that we
  control exactly what is done there, and the implementation is
  guaranteed to not use any code that is not async-signal-safe
  (unless the assertion fails, of course).

3) add NM_MORE_ASSERTS_EFFECTIVE.
  When using no glib (libnm-std-aux), the assert is implemented
  by C89 assert(), while libnm-glib-aux redirects that to g_assert().
  Note that these assertions are only in effect, if both NM_MORE_ASSERTS
  and NDEBUG/G_DISABLE_ASSERT say so. NM_MORE_ASSERTS_EFFECTIVE
  is thus the effectively used level for nm_assert().

4) use the proper __assert_fail() and g_assertion_message_expr()
  calls. __assert_fail() is not standard, but it is there for glibc
  and musl. So relying on this is probably fine. Otherwise, we will
  get a compilation error and notice it.
2022-10-25 13:12:48 +02:00
Thomas Haller
197963fba3
std-aux: add _nm_noreturn macro 2022-10-25 13:12:48 +02:00
Thomas Haller
5f3259b620
std-aux: add NM_ALIGN*() macros
Taken from systemd's ALIGN(), ALIGN_TO(), etc.
2022-10-25 10:58:56 +02:00
Thomas Haller
263832a455
std-aux: add nm_memcpy() helper for handling copy of zero bytes 2022-10-24 08:48:05 +02:00
Thomas Haller
0920355227
std-aux: workaround unused variable with clang and nm_auto macro
It also can happen with clang 15 and clang 12. Just silence the warning.

The problem is of course, that we miss if a variable is really unused.
2022-10-20 21:15:56 +02:00
Thomas Haller
b28c6ca30e
all: avoid "-Wunreachable-code-generic-assoc" warning with _Generic()
Clang 15 ([1], [2]) added

  Added the -Wunreachable-code-generic-assoc diagnostic flag (grouped
  under the -Wunreachable-code flag) which is enabled by default and warns
  the user about _Generic selection associations which are unreachable
  because the type specified is an array type or a qualified type.

This causes compiler warnings with various uses of _Generic():

  ../src/libnm-glib-aux/nm-shared-utils.h:2489:12: error: due to lvalue conversion of the controlling expression, association of type 'const char *const *const' will never be selected becaus
  e it is qualified [-Werror,-Wunreachable-code-generic-assoc]
      return nm_strv_find_first((const char *const *) strv->pdata, strv->len, str);
             ^
  ../src/libnm-glib-aux/nm-shared-utils.h:475:25: note: expanded from macro 'nm_strv_find_first'
      _nm_strv_find_first(NM_CAST_STRV_CC(list), (len), (needle))
                          ^
  ../src/libnm-glib-aux/nm-macros-internal.h:397:22: note: expanded from macro 'NM_CAST_STRV_CC'
                 const char *const*const: (const char *const*) (value), \
                       ^

Clang is correct.

[1] https://releases.llvm.org/15.0.0/tools/clang/docs/ReleaseNotes.html#improvements-to-clang-s-diagnostics
[2] https://reviews.llvm.org/D125259
2022-10-11 17:21:11 +02:00
Thomas Haller
2f0808a610
std-aux: add _nm_always_inline for "__attribute__((__always_inline__))" 2022-10-11 08:59:48 +02:00
Thomas Haller
afcfbe9973
std-aux: workaround unused variable warning with clang 14 and nm_auto cleanup attribute 2022-10-07 20:57:44 +02:00
Thomas Haller
efcc030752
std-aux/trivial: fix typo in code comment 2022-09-28 13:30:45 +02:00
Thomas Haller
04a97e4e85
std-aux: workaround maybe uninitialized warning with LTO on nm_ip_addr_is_null()
LTO without assertion enabled, thinks that certain code paths
result in uninitialized code. Technically, it's not wrong, in practice
those are only in cases where we already failed an assertion.

  In function 'nm_ip_addr_is_null',
      inlined from 'canonicalize_ip_binary' at src/libnm-core-impl/nm-setting-ip-config.c:67:21,
      inlined from 'nm_ip_route_set_next_hop_binary' at src/libnm-core-impl/nm-setting-ip-config.c:1062:23:
  ./src/libnm-glib-aux/nm-inet-utils.h:80:12: error: 'a' may be used uninitialized [-Werror=maybe-uninitialized]
     80 |     return IN6_IS_ADDR_UNSPECIFIED(&a.addr6);
        |            ^
  src/libnm-core-impl/nm-setting-ip-config.c: In function 'nm_ip_route_set_next_hop_binary':
  ./src/libnm-glib-aux/nm-inet-utils.h:73:14: note: 'a' declared here
     73 |     NMIPAddr a;
        |              ^

Try to workaround that by letting nm_utils_addr_family_to_size() always
return a non-zero size. This is ugly, because in the assertion case fail
we might now also get an additional memory corruption that could have
been avoided by returning zero. However, it probably doesn't matter, because
in this scenario we are already in a bad situation.

Fixes: b02aeaf2f3 ('glib-aux: fix various nm_ip_addr_*() functions for unaligned addresses')
2022-08-25 21:15:38 +02:00
Thomas Haller
49ddb96d4e
std-aux: add nm_utils_addr_family_to_size_untrusted() helper 2022-08-09 08:02:36 +02:00
Thomas Haller
8153b3ff0c
std-aux: use unique local variable in NM_IN_SET() macro
If you do:

  nm_assert_addr_family(NMP_OBJECT_CAST_MPTCP_ADDR(obj)->addr_family));

then there are two nested NM_IN_SET() macro invocations. Once,
NMP_OBJECT_CAST_MPTCP_ADDR() checks that the object type is one of
a few selected (using NM_IN_SET()). Then, that is passed to
nm_assert_addr_family(), which checks NM_IN_SET(addr_family, AF_INET,
AF_INET6).

In general, it's easy to end up in a situation like this.

And it mostly works just fine. The only problem was that NM_IN_SET()
uses an internal, local variable "_x". The compiler will emit a very
verbose failure about the shadowed variable:

  ./src/libnm-std-aux/nm-std-aux.h:802:14: error: declaration of '_x' shadows a previous local [-Werror=shadow]
    802 |         type _x = (x);                                                \

NM_UNIQ_T() exists for this purpose. Use it. NM_IN_SET() is
popular enough to warrant a special treatment to avoid this pitfall.
2022-07-28 13:07:50 +02:00
Thomas Haller
6501f741fc
std-aux: add argument to "op" parameter for NM_VA_ARGS_FOREACH() macro
This will be needed to pass "NM_UNIQ" to the op macro, to construct
a NM_UNIQ_T() unique name.
2022-07-28 13:06:08 +02:00
Thomas Haller
5c54bad89d
std-aux: add nm_memeq() helper 2022-07-28 11:06:53 +02:00
Thomas Haller
60404836d8
std-aux: add c_list_insert_sorted()
The strength of CList is of course to use it as a stack of queue,
and only append/remove from the front/tail.

However, since this is an intrusive list, it can also be useful to
just use it to track elements, and -- when necessary -- sort them
via c_list_sort().

If we have a sorted list, we might want to insert a new element
honoring the sort order. This function achieves that.
2022-07-28 11:05:14 +02:00
Thomas Haller
dc98ab807c
platform: include "linux-headers" via "libnm-std-aux/nm-linux-compat.h"
We have our own copy of linux kernel headers, and we must never
directly include the corresponding versions from the system.

Avoid that, by only including the clones via "libnm-std-aux/nm-linux-compat.h"
and by including the compat wrapper header before other system headers.
2022-07-26 12:28:04 +02:00
Thomas Haller
c4992c75f7
std-aux: use nm_memcmp() in NM_CMP_DIRECT_MEMCMP()
NM_CMP_DIRECT_MEMCMP() gets called by NM_CMP_FIELD_MEMCMP_LEN().
For example, if you want to compare a NMIPAddr, it seems sensible
to call

  NM_CMP_FIELD_MEMCMP_LEN(obj1, obj2, addr, nm_utils_addr_family_to_size(obj1->addr_family));

Granted, nm_utils_addr_family_to_size() asserts that addr_family is
either AF_INET or AF_INET6. However, if the assertion fails, we don't
want yet another undefined behavior here and do the sensible thing
about n zero.

In general, for a low-level function that uses memcmp(), it's non
obvious to ensure that the caller does not accidentally invoke undefined
behavior. nm_memcmp() avoids that.
2022-07-20 10:15:28 +02:00
Thomas Haller
2ebc3ac7d9
std-aux: add nm_memcmp() helper 2022-07-20 10:15:23 +02:00
Thomas Haller
921af527f7
std-aux: cleanup NM_CMP_*() macros
- add code comments explaining some things.

- for NM_CMP_FIELD*() variants have a corresponding NM_CMP_DIRECT*()
  macro and use it (aside the "memcmp" variants, which don't translate
  directly).
2022-06-09 09:52:51 +02:00
Thomas Haller
0b7dc4137d
std-aux: include default std-aux headers by "nm-default-std.h" 2022-05-09 19:20:19 +02:00
Thomas Haller
80a19958dc
code-style: fix wrong indentation for code comments 2022-05-09 19:20:18 +02:00
Thomas Haller
532f3e34a8
glib-aux: drop nm_str_buf_init() for NM_STR_BUF_INIT()
NM_STR_BUF_INIT() and nm_str_buf_init() were pretty much redundant. Drop one of
them.

Usually our pattern is that we don't have functions that return structs.
But NM_STR_BUF_INIT() returns a struct, because it's convenient to use
with

  nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(...);

So use that variant instead.
2022-05-09 19:18:30 +02:00
Thomas Haller
2c5bacd416
std-aux: add NM_UTILS_GET_NEXT_REALLOC_SIZE_488 define 2022-04-13 09:23:28 +02:00
Thomas Haller
f307e12080
std-aux: cast NM_IN_SET_SET() operands to "int" for "-Wbitwise-instead-of-logical" warning
Clang 14 has a new warning "-Wbitwise-instead-of-logical", and it warns
about our usage with NM_IN_SET_SE()/NM_IN_STRSET_SE(). It complains that we
are using '|' with boolean operands. Which is true (and intended), as we bitwise-or
the result of the '==' comparisons.

Work around the warning by casting the operands to "int". Note that
in C, the comparison operators have already a type "int", so this cast
should not result in any changes in the compiled code.

    ../src/libnm-core-impl/tests/test-general.c:9415:17: error: use of bitwise '|' with boolean operands [-Werror,-Wbitwise-instead-of-logical]
        _ASSERT(2, !NM_IN_SET_SE(-1, G(1), G(2)));
        ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ../src/libnm-std-aux/nm-std-aux.h:800:30: note: expanded from macro 'NM_IN_SET_SE'
    #define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof(x), x, __VA_ARGS__)
                                 ^
    ../src/libnm-std-aux/nm-std-aux.h:789:39: note: expanded from macro '_NM_IN_SET'
            !!(NM_VA_ARGS_FOREACH(, , op, _NM_IN_SET_OP, __VA_ARGS__)); \
                                          ^
    ../src/libnm-std-aux/nm-std-aux.h:772:20: note: expanded from macro 'NM_VA_ARGS_FOREACH'
                       op,                                                   \
                       ^
    note: (skipping 7 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
    ../src/libnm-glib-aux/nm-macros-internal.h:1603:47: note: expanded from macro '_G_BOOLEAN_EXPR'
    #define _G_BOOLEAN_EXPR(expr) NM_BOOLEAN_EXPR(expr)
                                  ~~~~~~~~~~~~~~~~^~~~~
    ../src/libnm-std-aux/nm-std-aux.h:167:62: note: expanded from macro 'NM_BOOLEAN_EXPR'
    #define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL(NM_UNIQ, expr)
                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
    ../src/libnm-std-aux/nm-std-aux.h:161:13: note: expanded from macro '_NM_BOOLEAN_EXPR_IMPL'
            if (expr)                      \
                ^~~~
    ../src/libnm-core-impl/tests/test-general.c:9415:17: note: cast one or both operands to int to silence this warning
    ../src/libnm-std-aux/nm-std-aux.h:800:30: note: expanded from macro 'NM_IN_SET_SE'
    #define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof(x), x, __VA_ARGS__)
                                 ^
    ../src/libnm-std-aux/nm-std-aux.h:789:39: note: expanded from macro '_NM_IN_SET'
            !!(NM_VA_ARGS_FOREACH(, , op, _NM_IN_SET_OP, __VA_ARGS__)); \
                                          ^
2022-03-16 00:57:17 +01:00
Thomas Haller
71f53d4069
std-aux: add code comment for NM_STR_HAS_PREFIX()/NM_STR_HAS_SUFFIX() 2022-03-09 09:10:45 +01:00
Thomas Haller
615221a99c format: reformat source tree with clang-format 13.0
We use clang-format for automatic formatting of our source files.
Since clang-format is actively maintained software, the actual
formatting depends on the used version of clang-format. That is
unfortunate and painful, but really unavoidable unless clang-format
would be strictly bug-compatible.

So the version that we must use is from the current Fedora release, which
is also tested by our gitlab-ci. Previously, we were using Fedora 34 with
clang-tools-extra-12.0.1-1.fc34.x86_64.

As Fedora 35 comes along, we need to update our formatting as Fedora 35
comes with version "13.0.0~rc1-1.fc35".
An alternative would be to freeze on version 12, but that has different
problems (like, it's cumbersome to rebuild clang 12 on Fedora 35 and it
would be cumbersome for our developers which are on Fedora 35 to use a
clang that they cannot easily install).

The (differently painful) solution is to reformat from time to time, as we
switch to a new Fedora (and thus clang) version.
Usually we would expect that such a reformatting brings minor changes.
But this time, the changes are huge. That is mentioned in the release
notes [1] as

  Makes PointerAligment: Right working with AlignConsecutiveDeclarations. (Fixes https://llvm.org/PR27353)

[1] https://releases.llvm.org/13.0.0/tools/clang/docs/ReleaseNotes.html#clang-format
2021-11-29 09:31:09 +00:00
Harald van Dijk
58bfcffd59 core: support linking with LLD 13
LLD 13 adds -z start-stop-gc and makes it the default, resulting in:

    CCLD     src/core/NetworkManager-all-sym
  ld.lld: error: undefined symbol: __stop_connection_defaults
  >>> referenced by nm-config.c:0 (src/core/nm-config.c:0)
  >>>               libNetworkManager_la-nm-config.o:(read_config) in archive src/core/.libs/libNetworkManager.a
  >>> referenced by nm-config-data.c:1598 (src/core/nm-config-data.c:1598)
  >>>               libNetworkManager_la-nm-config-data.o:(nm_config_data_get_connection_default) in archive src/core/.libs/libNetworkManager.a
  >>> referenced by nm-config-data.c:0 (src/core/nm-config-data.c:0)
  >>>               libNetworkManager_la-nm-config-data.o:(nm_config_data_get_connection_default) in archive src/core/.libs/libNetworkManager.a

  ld.lld: error: undefined symbol: __start_connection_defaults
  >>> referenced by nm-config.c:0 (src/core/nm-config.c:0)
  >>>               libNetworkManager_la-nm-config.o:(read_config) in archive src/core/.libs/libNetworkManager.a
  >>> referenced by nm-config.c:0 (src/core/nm-config.c:0)
  >>>               libNetworkManager_la-nm-config.o:(read_config) in archive src/core/.libs/libNetworkManager.a
  >>> referenced by nm-config.c:0 (src/core/nm-config.c:0)
  >>>               libNetworkManager_la-nm-config.o:(read_config) in archive src/core/.libs/libNetworkManager.a
  >>> referenced 2 more times
  clang: error: linker command failed with exit code 1 (use -v to see invocation)

Add __attribute__((__retain__)) to prevent GC of the connection
defaults.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1008
2021-11-02 12:42:51 +01:00
Thomas Haller
1c85bc5ead
std-aux: work around "-Wunused-but-set-variable" warning with clang in nm_auto()
We use the cleanup attribute heavily. It's useful for deferring
deallocation. For example, we have code like:

  gs_unref_object NMBluezManager *self_keep_alive = g_object_ref(self);

where we don't use the variable otherwise, except for owning (and
freeing) the reference. This already lead to a compiler warning about
unused variable, which we would workaround with

  _nm_unused gs_unref_object NMBluezManager *self_keep_alive = g_object_ref(self);

With clang 13.0.0~rc1-1.fc35, this got worse. Now for example also

    static inline void
    nm_strvarray_set_strv(GArray **array, const char *const *strv)
    {
        gs_unref_array GArray *array_old = NULL;

        array_old = g_steal_pointer(array);

        if (!strv || !strv[0])
            return;

        nm_strvarray_ensure(array);
        for (; strv[0]; strv++)
            nm_strvarray_add(*array, strv[0]);
    }

leads to a warning

    ./src/libnm-glib-aux/nm-shared-utils.h:3078:28: error: variable array_old set but not used [-Werror,-Wunused-but-set-variable]
        gs_unref_array GArray *array_old = NULL;
                               ^

This is really annoying. We don't want to plaster our code with _nm_unused,
because that might hide actual issues. But we also want to keep using this
pattern and need to avoid the warning.

A problem is also that GCC usually does not warn about truly unused
variables with cleanup attribute. Clang was very useful here to flag
such variables. But now clang warns about cases which are no bugs, which
is a problem. So this does loose some useful warnings. On the other hand,
a truly unused variable (with cleanup attribute) is ugly, but not an actual
problem.

Now, with clang 13, automatically mark nm_auto() variables as _nm_unused
as workaround.
2021-10-08 15:56:10 +02:00