There is no advantage in having these as macros. Make them
inline functions, compiler should be able to decide that they
are in fact inlinable.
Also, don't call g_strcmp0() for nm_streq0(). It means we first
have to call glib function, only to call a glibc function. No need
for this abstraction.
Contrary to g_str_has_suffix(), it exploits the fact the the suffix length
is known at compile time. No need to call a glib function, to find out what
we already know, to call strcmp().
Instead just calculate the string length and call memcmp().
There is:
1) glib's MAX() macro, which evaluates arguments multiple times,
but yields a constant expression, if the arguments are constant.
2) NM's NM_MAX() macro, which evaluates arguments exactly once,
but never yields a constant expression.
3) systemd's MAX() which is like NM_MAX().
Now, it's sensible to use
char buf[MAX (A_CONSTANT, ANOTHER_CONSTANT)];
and this works with glib's variant (1).
However, when we include systemd headers, 1) gets redefined to 3), and
above no longer works. That is because we we don't allow VLA and systemd's
macro gives not a constant expression.
Add NM_CONST_MAX() macro which is like systemd's CONST_MAX(). It can
only operate on constant arguments.
NM_UTILS_LOOKUP_STR() uses alloca(). Partly to avoid the overhead of
malloc(), but more important because it's convenient to use. It does
not require to declare a varible to manage the lifetime of the heap
allocation.
It's quite safe, because the stack allocation is of a fixed size of only
a few bytes. Overall, I think the convenience that we get (resulting in
simpler code) outweighs the danger of stack allocation in this case. It's
still worth it.
However, as it uses alloca(), it still must not be used inside a (unbound)
loop and it is obviously a macro.
Rename the macros to have a _A() suffix. This should make the
peculiarities more apparent.
Commonly, the prefix is a string constant. We don't need to call
g_str_has_prefix() for that, which first requires strlen() on
the prefix. All the information is readily available.
Add a macro for that.
C11 provides _Generic(). Until now we used it when the compiler supports
it (in extended --std=gnu99 mode). In practice, now that we require C11
it should always be present.
We will drop compatibility code in the future. For now, just add a comment
and keep it. The reason is, that "shared/nm-utils/nm-macros-internal.h"
may be used by VPN plugins or applet, which may or may not yet bump to
C11. Keeping it for now, allows for an easier update.
Preface: RFC 3442 (The Classless Static Route Option for Dynamic Host
Configuration Protocol (DHCP) version 4) states:
If the DHCP server returns both a Classless Static Routes option and
a Router option, the DHCP client MUST ignore the Router option.
Similarly, if the DHCP server returns both a Classless Static Routes
option and a Static Routes option, the DHCP client MUST ignore the
Static Routes option.
Changes:
- sd_dhcp_lease_get_routes() returns the combination of both option 33
(static routes) and 121 (classless static routes). If classless static
routes are provided, the state routes must be ignored.
- we collect the options hash that we expose on D-Bus. For that purpose,
we must not merge both option types as classless static routes. Instead,
we want to expose the values like we received them originally: as two
different options.
- we continue our deviation from RFC 3442, when receiving classless static
routes with option 3 (Router), we only ignore the router if we didn't
already receive a default route via classless static routes.
- in the past, NetworkManager treated the default route specially, and
one device could only have one default route. That limitation was
already (partly) lifted by commit 5c299454b4
(core: rework tracking of gateway/default-route in ip-config). However,
from DHCP we still would only accept one default route. Fix that for
internal client. Installing multiple default routes might make sense, as
kernel apparently can skip unreachable routers (as it notes via ICMP
messages) (rh#1634657).
https://bugzilla.redhat.com/show_bug.cgi?id=1634657
From [1]:
You may optionally specify attribute names with ‘__’ preceding and
following the name. This allows you to use them in header files
without being concerned about a possible macro of the same name. For
example, you may use the attribute name __noreturn__ instead of
noreturn.
[1] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax
Add a new CON_DEFAULT() macro that places a property name into a
special section used at runtime to check whether it is a supported
connection default.
Unfortunately, this mechanism doesn't work for plugins so we have to
enumerate the connection defaults from plugins in the daemon using
another CON_DEFAULT_NOP() macro.
Supporting a trailing comma in NM_MAKE_STRV() can be desirable, because it
allows to extend the code with less noise in the diff.
Now, there may or may not be a trailing comma at the end.
There is a downside to this: the following no longer work:
const char *const v1[] = NM_MAKE_STRV ("a", "b");
const char *const v2[3] = NM_MAKE_STRV ("a", "b");
but then, above can be written more simply already as:
const char *const v1[] = { "a", "b", NULL };
const char *const v2[3] = { "a", "b" };
so the fact that the macro won't work in that case may be preferable,
because it forces you to use the already existing better variant.
Refactor the check so that integer overflow cannot happen. Realistically,
it anyway couldn't happen, because _name is nowhere near the size of
G_MAXSIZE. Still, avoid such code. Also, the operands involved here are
constants, so the extra check can anyway be resolved at compile-time.
In general, it's fine to pass %NULL to g_free().
However, consider:
char *
foo (void)
{
gs_free char *value = NULL;
value = g_strdup ("hi");
return g_steal_pointer (&value);
}
gs_free, gs_local_free(), and g_steal_pointer() are all inlinable.
Here the compiler can easily recognize that we always pass %NULL to
g_free(). But with the previous implementation, the compiler would
not omit the call to g_free().
Similar patterns happen all over the place:
gboolean
baz (void)
{
gs_free char *value = NULL;
if (!some_check ())
return FALSE;
value = get_value ();
if (!value)
return FALSE;
return TRUE;
}
in this example, g_free() is only required after setting @value to
non-NULL.
Note that this does increase the binary side a bit (4k for libnm, 8k
for NetworkManager, with "-O2").
PROP_0 is how we commonly name this property when we don't use
NM_GOBJECT_PROPERTIES_DEFINE(). Rename it.
Also, allow to skip PROP_0 in nm_gobject_notify_together(), that
is handy to optionally invoke a notification, like
nm_gobject_notify_together (obj,
PROP_SOMETHING,
changed ? PROP_OTHER : PROP_0);
We already had nm_free_secret() to clear the secret out
of a NUL terminated string. That works well for secrets
which are strings, it can be used with a cleanup attribute
(nm_auto_free_secret) and as a cleanup function for a
GBytes.
However, it does not work for secrets which are binary.
For those, we must also track the length of the allocated
data and clear it.
Add two new structs NMSecretPtr and NMSecretBuf to help
with that.
Internally, GByteArray is actually a GArray, so it would be safe to
use "gs_unref_array" macro. However, that is rather ugly, and means
to rely on an internal implementation detail of GByteArray.
Instead, add a cleanup macro for GByteArray.
NM_GOBJECT_PROPERTIES_DEFINE() defines a helper function
_notify() to emit a GObject property changed notification.
Add another helper function to emit multiple notifications
together, and freeze/thaw the notification before.
This is particularly useful, because our D-Bus glue in
"nm-dbus-object.c" hooks into dispatch_properties_changed(),
to emit a combined PropertiesChanged signal for multiple
properties. By carefully freezing/thawing the notifications,
the exported objects can combine changes of multiple properties
in one D-Bus signal.
This helper is here to make that simpler.
Note that the compiler still has no problem to inline _notify()
entirey. So, in a non-debug build, there is little difference in
the generated code. It can even nicely inline calls like
nm_gobject_notify_together (self, PROP_ADDRESS_DATA,
PROP_ADDRESSES);
We only have a certain granularity of how our headers in "shared/nm-utils"
can be used independently.
For example, it's not supported to use "nm-macros-internal.h" without
"gsystem-local-alloc.h". Likewise, you cannot use "nm-glib.h" directly,
you always get it together with "nm-macros-internal.h".
This is, we don't support to use certain headers entirely independently,
because usually you anyway want to use them together.
As such, no longer support "gsystem-local-alloc.h", but merge the
remainder into "nm-macros-internal.h". There is really no reason
to support arbitrary flexibility of including individual bits. You
want cleanup-macros? Include "nm-macros-internal.h".
Merge the headers.
These cleanup macros are unused by NetworkManager code. Note that
since "shared/nm-utils" is used by applet and VPN plugins, theoretically,
they could be used there. I didn't check that, but breaking API of
"shared/nm-utils" is fine (as long as we catch it with a compilation
error).
Historically, we use libgsystem's gsystem-local-alloc header and their
"gs_*" macros. However, they are not really our style and don't have
a nm-prefix (like the rest of our code). We keep the gs_ names, because
they are wildly used and because we wanted to keep gsystem-local-alloc
in sync with upstream (which is no longer the case).
Our own cleanup macros are always called "nm_auto_*". So, at least
for the unused "gs_*" macros, rename them to "nm_auto_*".
Don't drop them, despite they being unused. The reason is, that we should
make use of cleanup functions more eagerly. Dropping them now -- because
they are momentarily unused -- hampers using them in the future. We
often don't use the cleanup macros at places where I think we should,
so by dropping them, we hamper future use.
At various places, use the correct type for the pointer, this
allows the compiler to be more helpful.
For gs_free, gs_unref_object, and nm_auto_free, the pointer type is
of course still 'void *'.
This catches wrong uses like
gs_strfreev char *wrong1 = NULL;
gs_strfreev const char **wrong2 = NULL;
gs_free_error GError **p_error = NULL;
gs_unref_array GPtrArray *ptr_array = NULL;
Note that long time ago we copied "gsystem-local-alloc.h" header
from libgsystem library. Until now, we didn't apply any local
modification to this file, to keep it in sync with upstream.
However, upstream libgsystem is not maintained anymore, so there
is no reason to stay in sync with upstream.
This really is the same as gs_strfreev / g_strfreev().
However, the difference is, that the former has the notion
of freeing strv arrays (char **), while this in general
frees an array of pointers. Implementation-wise, they are
the same.
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
Also, assign *_pp before unref-ing the old value. Calling
g_object_unref() on the old value, might invoke callbacks
that are out of control of nm_g_object_ref_set(). During
that time, the pointer should already be assigned the new value,
instead of having an intermediate %NULL value. In most cases,
this would of course not matter, but there is no need to let
anyone see an intermediate %NULL value for a moment.
Also, don't use typeof(**_pp), which would not work with opaque
types (like we commonly have).
For one, these functions are not often needed. No need to define them in the
"nm-macros-internal.h" header, which is included everywhere. Move them to
"nm-shared-utils.h", which must be explicitly included.
Also, these functions are usually not called directly, but by passing their
function pointer to a sort function or similar. There is no point in having
defined in the header file.
Previously, NM_PTRARRAY_LEN() would not work if the pointer type is
an opaque type, which is common. For example:
NMConnection *const*connections = ...;
Add an alternative to g_clear_pointer(). The differences are:
- nm_clear_pointer() is more type safe as it does not cast neither the
pointer nor the destroy function. Commonly, the types should be compatible
and not requiring a cast. Casting in the macro eliminates some of the
compilers type checking. For example, while
g_clear_pointer (&priv->hash_table, g_ptr_array_unref);
compiles, nm_clear_pointer() would prevent such an invalid use.
- also, clear the destination pointer *before* invoking the destroy
function. Destroy might emit signals (like weak-pointer callbacks
of GArray clear functions). Clear the destination first, so that
we don't leave a dangling pointer there.
- return TRUE/FALSE depending on whether there was a pointer to clear.
I tested that redefining g_clear_pointer()/g_clear_object() with our
more typesafe nm_* variants still compiles and indicates no bugs. So
that is good. It's not really expected that turning on more static checks
would yield a large number of bugs, because generally our code is in a good
shape already. We have few such bugs, because we already turn all all warnings
and extra checks that make sense. That however is not an argument for
not introducing (and using) a more resticted implementation.
It's slightly more correct to first clear the pointer location
before invoking the destroy function. The destroy function might
emit other callbacks, and at a certain point the pointer becomes
dangling. Avoid this danling pointer, by first clearing the
memory, and then destroing the instance.
Add macros that cast away the constness of a pointer, but
ensure that the type of the pointer is as expected.
Unfortunately, there is no way (AFAIK) to remove the constness of
a variable, without explicitly passing @type to the macro.