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.
Allow to initialize NMStrBuf with an externally allocated array.
Usually a stack buffer. If the NMStrBuf grows beyond the size of
that initial buffer, then it would switch using malloc.
The idea is to support the common case where the result is small enough
to fit on the stack.
I always wanted to do such optimization because the main purpose of
NMStrBuf is to put it on the stack and ad-hoc construct a string.
I just figured, it would complicate the implementation and add
a runtime overhead. But turns out, it doesn't really.
The biggest question is how NMStrBuf should behave with a pre-allocated
buffer? Turns out, most choices can be made in a rather obvious way.
The only non-obvious thing is that nm_str_buf_finalize() would malloc()
a buffer, but that too seems consistent and what a user would probably
expect. As such, this doesn't seem to add unexpected semantics to the API.
On glibc, HOST_NAME_MAX is defined as 64. Also, Linux'
sethostname() enforces that limit (__NEW_UTS_LEN). Also,
`man gethostname` comments that HOST_NAME_MAX on Linux is
64.
However, when building against musl, HOST_NAME_MAX is defined as 255.
That seems wrong. We use this limit to validate the hostname, and that
should not depend on the libc or on the compilation.
Hardcode the value to 64.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1197
nm_hostname_is_valid() determines the valid length based on
HOST_NAME_MAX, which is defined differently for glibc and musl.
Fixes: 9ff1f66680 ('glib-aux: add nm_hostname_is_valid() helper from systemd')
We use these functions, currently from our systemd fork. One day we want
to stop importing systemd code, so we need them ourselves.
Copy them, and adjust for NM style.
This seams easier to read. And as we have a unit test that covers all
possible 256 input values, it's easy to refactor and ensure the code
still works.
We effectively already have this function, with the name
nm_utils_named_values_from_strdict(). Which is a decent name,
if you have a strdict. But it seems odd to use for other dictionaries.
Instead, add a variant with a different name. Naming is important,
and just to have the better name, the function is effectively duplicated.
NMUtilsNamedValue is a key-value tuple, usually the key is a string
(hence the name "Named").
But this struct is also useful for keys that are not strings.
Add another "name_ptr" union field to access the key that way.
The alternative would be to add another struct, which serves
a very similar purpose though.
We write lease files for internal DHCP client ("systemd" and "nettools")
in a systemd-specific format. We want to drop systemd code, so we need
to have our own parsing code.
Granted, nettools only writes a single "ADDRESS=" line, so parsing that
would be easy. On the other hand, systemd's parser is not complicated
either (in particular, if we can steal their implementation). Also, it's
a commonly used format in systemd, so having the parser would allow us
to parse similar formats.
Also, we could opt to choose that format, where it makes sense.
Of course, the prefix length cannot be larger than 32 or 128.
But as C does implicit conversions, a buggy prefix length can
lead to a (wrongly) valid prefix length.
Make the type uint32, to prevent that (at least for common cases,
unless you pass a huge 64 bit integer).
For convenience, most to-string methods call nm_utils_to_string_buffer_init().
This allows to omit the string buffer and use a global (thread-local)
buffer.
That "convenience" seems error prone. Start drop it.
Start by adding a g_return_if_reached() assertion to catch the cases
that use it.
I want to get rid of "_nm_utils_to_string_buffer" (or at least, limit
and control its use). Currently it's used all over the place only
to get the size of it. Add a define instead.
It has no actual dependency on the crypto library. All it does, is
to be careful about not leaking secrets in memory. We have code
for that in libnm-glib-aux already. Move.
The goal is to reduce the number of places where we use libnm-crypto,
because that has a large dependency. libnm-glib-aux is a very light
dependency instead.
nm_utils_bin2hexstr() is part of public libnm API.
That means, if we want to use this function, we need to link with
libnm-core-impl.
This is used by "nm-crypto.c". That file is currently part of
libnm-core, but that will change.
Move the implementation to libnm-glib-aux, so that we can use this code
from all our glib-based code (because all our glib-based code is allowed
to link with libnm-glib-aux).
If __VA_ARGS__ contains odd arguments, it's not clear that N_ARG() gives
the same as the array initialization. Add a static assert that the
numbers agree to catch wrong usage of the macro.
For example:
nm_gobject_notify_together(setting, a, b, );
g_idle_add() uses G_PRIORITY_DEFAULT_IDLE priority. Most of the time we don't
care much about the priority.
But at the places that this patch changes, I think that using
G_PRIORITY_DEFAULT_IDLE (and following g_idle_add()) is more correct. The
reason for this is not very strong, except that it's probably the better
choice. And the old choice was made because I didn't realize that
g_idle_add() uses another default priority. Hence, the old choice was not
for good reasons either.
nm_g_idle_add_source() is supposed to work like g_idle_add(). Use the correct
priority.
I think this causes little actual problems, because usually we don't
carefully tune the priorities and would be mostly fine with either.
Fixes: 6b18fc252d ('shared: add nm_g_{idle,timeout}_add_source() helpers')
For one, this API is only available since 2.72, thus we must not use
it (unless we would add a compat implementation to nm-glib.h).
But also, g_alloca0() evaluates the size argument multiple times,
making it non-function like. That seems highly undesirable and error
prone.
Also, we should be very careful about alloca() and the potential
for stack overflow. We use alloca() at times, but usually with
macros that are named "*_a()" (to make the danger clearer) and compile
time checks for the size. These glib functions make this slightly
less safe.
Just prevent us from using this API.
What nm_uuid_generate_from_string() does, is pretty straight forward.
What nm_crypto_md5_hash() does, is not.
Just directly use GChecksum, it seems clearer.
Also, sometimes the compiler is adamant to warn about uninitialized variables.
The workaround from commit cb9ca67901 ('glib-aux: workaround maybe-uninitialized
warning with LTO in nm_uuid_generate_from_string_str()') does not always work.
Try to solve that this way.
Note that we have plenty of unit tests for our UUID generation. This is
covered by tests.
Also, there is now only one caller of nm_crypto_md5_hash() left. Which
is good, because that function is rather non-obvious and special purpose.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1129
gcc-12.0.1-0.8.fc36 is annoying with false positives.
It's related to g_error() and its `for(;;) ;`.
For example:
../src/libnm-glib-aux/nm-shared-utils.c: In function 'nm_utils_parse_inaddr_bin_full':
../src/libnm-glib-aux/nm-shared-utils.c:1145:26: error: dangling pointer to 'error' may be used [-Werror=dangling-pointer=]
1145 | error->message);
| ^~
/usr/include/glib-2.0/glib/gmessages.h:343:32: note: in definition of macro 'g_error'
343 | __VA_ARGS__); \
| ^~~~~~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1133:31: note: 'error' declared here
1133 | gs_free_error GError *error = NULL;
| ^~~~~
/usr/include/glib-2.0/glib/gmessages.h:341:25: error: dangling pointer to 'addrbin' may be used [-Werror=dangling-pointer=]
341 | g_log (G_LOG_DOMAIN, \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
342 | G_LOG_LEVEL_ERROR, \
| ~~~~~~~~~~~~~~~~~~~~~~~
343 | __VA_ARGS__); \
| ~~~~~~~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1141:13: note: in expansion of macro 'g_error'
1141 | g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by "
| ^~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1112:14: note: 'addrbin' declared here
1112 | NMIPAddr addrbin;
| ^~~~~~~
I think the warning could potentially be useful and prevent real bugs.
So don't disable it altogether, but go through the effort to suppress it
at the places where it currently happens.
Note that NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER macro only expands
to suppressing the warning with __GNUC__ equal to 12. The purpose is to
only suppress the warning where we know we want to. Hopefully other gcc
versions don't have this problem.
I guess, we could also write a NM_COMPILER_WARNING() check in
"m4/compiler_options.m4", to disable the warning if we detect it. But
that seems too cumbersome.
New gcc-12.0.1-0.8.fc36 on Fedora rawhide likes to emit false
"-Wdangling-pointer" warnings with some g_error() uses. It seems
related to g_error()'s `for(;;) ;`.
As workaround, add a macro to suppress the warning.
But only do that for gcc-12. This bug hopefully gets fixed
and we don't want to suppress useful warnings too eagerly.
https://bugzilla.redhat.com/show_bug.cgi?id=2056613
Also, combine the different macros in the same #if/#else block.
The point of this is if you have a macro that does conditionally
NM_PRAGMA_WARNING_DISABLE(), then we need a way to balance the
push/pop.
G_TYPE_STRV is the last property type in NMSetting that is implemented
by directly accessing the GObect property. Note that we have lots of
override, non-default implementations that still use GObject properties,
but I am talking here about properties that don't have a special
implementation and use a G_TYPE_STRV GObject property.
Add a "direct" implementation also for strv arrays.
The advantage is that we no longer call g_value_get() for various
operations, which requires a deep-copy of the strv array. The other
advantage is that we will get a unified approach for implementing strv
properties. In particular strv arrays need a lot of code to implement,
and most settings do it differently. By adding a general mechanism,
this code (and behavior) can be unified.
Showcase it on "match.interface-name".
First of all, all of NMVariantAttributeSpec is internal API. We only
expose the typedef itself as public API, but not its fields nor
their meaning. So we can change things.
Change "str_type" to "type_detail", so that it can work for any kind of
attribute, not only for strings. Usually, we want to avoid special
cases and treat all attributes the same, based on their GVariant type.
But sometimes, it is necessary to do something special with an
attribute. This is what the "type_detail" encodes, but it's not only
relevant for strings.
We don't run glib-mkenums for certain sources like "core" and
"libnm-glib-aux".
These annotations have no effect. Drop them.
They also mess with the automated formatting.
In function 'nm_uuid_unparse',
inlined from 'nm_uuid_generate_from_string_str' at src/libnm-glib-aux/nm-uuid.c:393:12,
inlined from 'nm_uuid_generate_from_strings.constprop' at src/libnm-glib-aux/nm-uuid.c:430:16:
src/libnm-glib-aux/nm-uuid.h:37:12: error: 'uuid' may be used uninitialized [-Werror=maybe-uninitialized]
37 | return nm_uuid_unparse_case(uuid, out_str, FALSE);
| ^
src/libnm-glib-aux/nm-uuid.c: In function 'nm_uuid_generate_from_strings.constprop':
src/libnm-glib-aux/nm-uuid.c:20:1: note: by argument 1 of type 'const struct NMUuid *' to 'nm_uuid_unparse_case.constprop' declared here
20 | nm_uuid_unparse_case(const NMUuid *uuid, char out_str[static 37], gboolean upper_case)
| ^
src/libnm-glib-aux/nm-uuid.c:390:12: note: 'uuid' declared here
390 | NMUuid uuid;
| ^
lto1: all warnings being treated as errors
The problem are code paths with failed g_return*() assertions. Being in
a bad state already, they don't bother to ensure proper return values,
and with LTO the compiler might think there are valid code paths wrongly
handled. Work around.