shared: add nm_g_object_ref_set() and nm_clear_g_object()

- nm_clear_g_object() is like g_clear_object() but:

  - it returns a boolean value, indicating that something was cleared.

  - it includes an nm_assert() to check that the pointer is still
    valid.

  - it uses typeof() instead of blindly casting the argument.

- nm_g_object_ref_set() combines nm_clear_g_object() and resetting
  the pointer to a new object, including taking a reference.

  - also returns a boolean, indicating whether something changed.

  - it gets the order of operations right: first it increses the
    ref-count, before unrefing the old object.

  - like nm_clear_g_object() and nm_clear_g_free() it first sets
    the destination to NULL, instead of leaving a dangling pointer
    for the duraction of the unref/free call.

- fix nm_clear_g_free() not to use a possibly dangling pointer.
  Striclty speaking, that is undefined behavior.
This commit is contained in:
Thomas Haller 2017-09-06 15:32:52 +02:00
parent 19716df23d
commit 959944d623

View file

@ -619,6 +619,36 @@ nm_g_object_unref (gpointer obj)
g_object_unref (obj);
}
/* Assigns GObject @obj to destination @pdst, and takes an additional ref.
* The previous value of @pdst is unrefed.
*
* It makes sure to first increase the ref-count of @obj, and handles %NULL
* @obj correctly.
* */
#define nm_g_object_ref_set(pp, obj) \
({ \
typeof (*(pp)) *const _pp = (pp); \
typeof (**_pp) *const _obj = (obj); \
typeof (**_pp) *_p; \
gboolean _changed = FALSE; \
\
if ( _pp \
&& ((_p = *_pp) != _obj)) { \
if (_obj) { \
nm_assert (G_IS_OBJECT (_obj)); \
g_object_ref (_obj); \
} \
if (_p) { \
nm_assert (G_IS_OBJECT (_p)); \
*_pp = NULL; \
g_object_unref (_p); \
} \
*_pp = _obj; \
_changed = TRUE; \
} \
_changed; \
})
/* basically, replaces
* g_clear_pointer (&location, g_free)
* with
@ -631,13 +661,32 @@ nm_g_object_unref (gpointer obj)
#define nm_clear_g_free(pp) \
({ \
typeof (*(pp)) *_pp = (pp); \
typeof (**_pp) *_p = *_pp; \
typeof (**_pp) *_p; \
gboolean _changed = FALSE; \
\
if (_p) { \
if ( _pp \
&& (_p = *_pp)) { \
*_pp = NULL; \
g_free (_p); \
_changed = TRUE; \
} \
!!_p; \
_changed; \
})
#define nm_clear_g_object(pp) \
({ \
typeof (*(pp)) *_pp = (pp); \
typeof (**_pp) *_p; \
gboolean _changed = FALSE; \
\
if ( _pp \
&& (_p = *_pp)) { \
nm_assert (G_IS_OBJECT (_p)); \
*_pp = NULL; \
g_object_unref (_p); \
_changed = TRUE; \
} \
_changed; \
})
static inline gboolean