summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-01-09 08:42:56 +0100
committerThomas Haller <thaller@redhat.com>2020-07-09 11:47:05 +0200
commitc0c10896e95c9ffc76e556a78f6cc883a4096b19 (patch)
tree6f58a70033bd05f72d8bbf77e98b79becb471ba7
parent3e5fc04df320486b0f395fe6898c86f4c0144e05 (diff)
downloadNetworkManager-c0c10896e95c9ffc76e556a78f6cc883a4096b19.tar.gz
libnm: introduce NMJsonVt virtual table for accessing libjansson symbols
Rework the code how we access libjansson. libnm wants to use libjansson, but it doesn't directly link to it. The reason is that (until recently), libjansson has conflicting symbols with libjson-c and libjson-glib. That means, if libnm would directly link against libjansson, then if the using application happens to drag in one of the conflicting libraries, the application would crash. Instead, we dlopen() the library (with flags RTLD_LOCAL|RTLD_DEEPBIND). However, as it is currently done, it doesn't fully work, as unit test failures of libnm show on Debian sid (where libmount links against libcryptsetup which links against libjson-c). Theoretically, our current approach should work. At least for libnm; not for the OVS and team plugins which use libjansson directly in NetworkManager core. What I dislike about the current approach is that we still include <jansson.h>, but somehow try not to use any symbols from it (via #define we remap the json functions). The previous approach is "smaller", but also highly confusing, and error prone, as there is a subtle bug as the unit test failure shows (which I don't understand). Instead, add and load a virtual function table NMJsonVt. Later, we will go further ad drop all direct uses of <jansson.h> header.
-rw-r--r--libnm-core/nm-json.c234
-rw-r--r--libnm-core/nm-json.h115
-rw-r--r--libnm-core/nm-team-utils.c2
-rw-r--r--libnm-core/nm-utils.c2
4 files changed, 241 insertions, 112 deletions
diff --git a/libnm-core/nm-json.c b/libnm-core/nm-json.c
index 001d53dbb6..f20027a0bd 100644
--- a/libnm-core/nm-json.c
+++ b/libnm-core/nm-json.c
@@ -5,106 +5,174 @@
#include "nm-default.h"
-#define NM_JANSSON_C
#include "nm-json.h"
#include <dlfcn.h>
-void *_nm_jansson_json_object_iter_value;
-void *_nm_jansson_json_object_key_to_iter;
-void *_nm_jansson_json_integer;
-void *_nm_jansson_json_object_del;
-void *_nm_jansson_json_array_get;
-void *_nm_jansson_json_array_size;
-void *_nm_jansson_json_array_append_new;
-void *_nm_jansson_json_string;
-void *_nm_jansson_json_object_iter_next;
-void *_nm_jansson_json_loads;
-void *_nm_jansson_json_dumps;
-void *_nm_jansson_json_object_iter_key;
-void *_nm_jansson_json_object;
-void *_nm_jansson_json_object_get;
-void *_nm_jansson_json_array;
-void *_nm_jansson_json_false;
-void *_nm_jansson_json_delete;
-void *_nm_jansson_json_true;
-void *_nm_jansson_json_object_size;
-void *_nm_jansson_json_object_set_new;
-void *_nm_jansson_json_object_iter;
-void *_nm_jansson_json_integer_value;
-void *_nm_jansson_json_string_value;
+typedef struct {
+ NMJsonVt vt;
+ void *dl_handle;
+} NMJsonVtInternal;
-#define TRY_BIND_SYMBOL(symbol) \
- G_STMT_START { \
- void *sym = dlsym (handle, #symbol); \
- if (_nm_jansson_ ## symbol && sym != _nm_jansson_ ## symbol) \
- return FALSE; \
- _nm_jansson_ ## symbol = sym; \
- } G_STMT_END
-
-static gboolean
-bind_symbols (void *handle)
+static NMJsonVtInternal *
+_nm_json_vt_internal_load (void)
{
- TRY_BIND_SYMBOL (json_object_iter_value);
- TRY_BIND_SYMBOL (json_object_key_to_iter);
- TRY_BIND_SYMBOL (json_integer);
- TRY_BIND_SYMBOL (json_object_del);
- TRY_BIND_SYMBOL (json_array_get);
- TRY_BIND_SYMBOL (json_array_size);
- TRY_BIND_SYMBOL (json_array_append_new);
- TRY_BIND_SYMBOL (json_string);
- TRY_BIND_SYMBOL (json_object_iter_next);
- TRY_BIND_SYMBOL (json_loads);
- TRY_BIND_SYMBOL (json_dumps);
- TRY_BIND_SYMBOL (json_object_iter_key);
- TRY_BIND_SYMBOL (json_object);
- TRY_BIND_SYMBOL (json_object_get);
- TRY_BIND_SYMBOL (json_array);
- TRY_BIND_SYMBOL (json_false);
- TRY_BIND_SYMBOL (json_delete);
- TRY_BIND_SYMBOL (json_true);
- TRY_BIND_SYMBOL (json_object_size);
- TRY_BIND_SYMBOL (json_object_set_new);
- TRY_BIND_SYMBOL (json_object_iter);
- TRY_BIND_SYMBOL (json_integer_value);
- TRY_BIND_SYMBOL (json_string_value);
-
- return TRUE;
-}
-
-gboolean
-nm_jansson_load (void)
-{
- static enum {
- UNKNOWN,
- AVAILABLE,
- MISSING,
- } state = UNKNOWN;
- void *handle;
+ NMJsonVtInternal *v;
+ void *handle = NULL;
int mode;
- if (G_LIKELY (state != UNKNOWN))
- goto out;
+ v = g_new0 (NMJsonVtInternal, 1);
- /* First just resolve the symbols to see if there's a conflict already. */
- if (!bind_symbols (RTLD_DEFAULT))
- goto out;
+#ifndef JANSSON_SONAME
+#define JANSSON_SONAME ""
+#endif
mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE | RTLD_DEEPBIND;
#if defined (ASAN_BUILD)
/* Address sanitizer is incompatible with RTLD_DEEPBIND. */
mode &= ~RTLD_DEEPBIND;
#endif
- handle = dlopen (JANSSON_SONAME, mode);
+
+ if (strlen (JANSSON_SONAME) > 0)
+ handle = dlopen (JANSSON_SONAME, mode);
if (!handle)
- goto out;
+ return v;
+
+#define TRY_BIND_SYMBOL(symbol) \
+ G_STMT_START { \
+ void *_sym = dlsym (handle, "json" #symbol); \
+ \
+ if (!_sym) \
+ goto fail_symbol; \
+ v->vt.nm_json ## symbol = _sym; \
+ } G_STMT_END
+
+ TRY_BIND_SYMBOL (_array);
+ TRY_BIND_SYMBOL (_array_append_new);
+ TRY_BIND_SYMBOL (_array_get);
+ TRY_BIND_SYMBOL (_array_size);
+ TRY_BIND_SYMBOL (_delete);
+ TRY_BIND_SYMBOL (_dumps);
+ TRY_BIND_SYMBOL (_false);
+ TRY_BIND_SYMBOL (_integer);
+ TRY_BIND_SYMBOL (_integer_value);
+ TRY_BIND_SYMBOL (_loads);
+ TRY_BIND_SYMBOL (_object);
+ TRY_BIND_SYMBOL (_object_del);
+ TRY_BIND_SYMBOL (_object_get);
+ TRY_BIND_SYMBOL (_object_iter);
+ TRY_BIND_SYMBOL (_object_iter_key);
+ TRY_BIND_SYMBOL (_object_iter_next);
+ TRY_BIND_SYMBOL (_object_iter_value);
+ TRY_BIND_SYMBOL (_object_key_to_iter);
+ TRY_BIND_SYMBOL (_object_set_new);
+ TRY_BIND_SYMBOL (_object_size);
+ TRY_BIND_SYMBOL (_string);
+ TRY_BIND_SYMBOL (_string_value);
+ TRY_BIND_SYMBOL (_true);
+
+ v->vt.loaded = TRUE;
+ v->dl_handle = handle;
+ return v;
+
+fail_symbol:
+ dlclose (&handle);
+ *v = (NMJsonVtInternal) { };
+ return v;
+}
- /* Now do the actual binding. */
- if (!bind_symbols (handle))
- goto out;
+const NMJsonVt *_nm_json_vt_ptr = NULL;
- state = AVAILABLE;
-out:
- return state == AVAILABLE;
+const NMJsonVt *
+_nm_json_vt_init (void)
+{
+ NMJsonVtInternal *v;
+
+again:
+ v = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+ if (G_UNLIKELY (!v)) {
+ v = _nm_json_vt_internal_load ();
+ if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, NULL, v)) {
+ if (v->dl_handle)
+ dlclose (v->dl_handle);
+ g_free (v);
+ goto again;
+ }
+
+ /* we transfer ownership. */
+ }
+
+ nm_assert (v && v == g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr));
+ return &v->vt;
}
+
+const NMJsonVt *
+nmtst_json_vt_reset (gboolean loaded)
+{
+ NMJsonVtInternal *v_old;
+ NMJsonVtInternal *v;
+
+ v_old = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+
+ if (!loaded) {
+ /* load a fake instance for testing. */
+ v = g_new0 (NMJsonVtInternal, 1);
+ } else
+ v = _nm_json_vt_internal_load ();
+
+ if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, v_old, v))
+ g_assert_not_reached ();
+
+ if (v_old) {
+ if (v_old->dl_handle)
+ dlclose (v_old->dl_handle);
+ g_free ((gpointer *) v_old);
+ }
+
+ return v->vt.loaded ? &v->vt : NULL;
+}
+
+#define DEF_FCN(name, rval, args_t, args_v) \
+rval name args_t \
+{ \
+ const NMJsonVt *vt = nm_json_vt (); \
+ \
+ nm_assert (vt && vt->loaded && vt->name); \
+ nm_assert (vt->name != name); \
+ return (vt->name) args_v; \
+}
+
+#define DEF_VOI(name, args_t, args_v) \
+void name args_t \
+{ \
+ const NMJsonVt *vt = nm_json_vt (); \
+ \
+ nm_assert (vt && vt->loaded && vt->name); \
+ nm_assert (vt->name != name); \
+ (vt->name) args_v; \
+}
+
+DEF_FCN (nm_json_array, json_t *, (void), ());
+DEF_FCN (nm_json_array_append_new, int, (json_t *json, json_t *value), (json, value));
+DEF_FCN (nm_json_array_get, json_t *, (const json_t *json, size_t index), (json, index));
+DEF_FCN (nm_json_array_size, size_t, (const json_t *json), (json));
+DEF_VOI (nm_json_delete, (json_t *json), (json));
+DEF_FCN (nm_json_dumps, char *, (const json_t *json, size_t flags), (json, flags));
+DEF_FCN (nm_json_false, json_t *, (void), ());
+DEF_FCN (nm_json_integer, json_t *, (json_int_t value), (value));
+DEF_FCN (nm_json_integer_value, json_int_t, (const json_t *json), (json));
+DEF_FCN (nm_json_loads, json_t *, (const char *string, size_t flags, json_error_t *error), (string, flags, error));
+DEF_FCN (nm_json_object, json_t *, (void), ());
+DEF_FCN (nm_json_object_del, int, (json_t *json, const char *key), (json, key));
+DEF_FCN (nm_json_object_get, json_t *, (const json_t *json, const char *key), (json, key));
+DEF_FCN (nm_json_object_iter, void *, (json_t *json), (json));
+DEF_FCN (nm_json_object_iter_key, const char *, (void *iter), (iter));
+DEF_FCN (nm_json_object_iter_next, void *, (json_t *json, void *iter), (json, iter));
+DEF_FCN (nm_json_object_iter_value, json_t *, (void *iter), (iter));
+DEF_FCN (nm_json_object_key_to_iter, void *, (const char *key), (key));
+DEF_FCN (nm_json_object_set_new, int, (json_t *json, const char *key, json_t *value), (json, key, value));
+DEF_FCN (nm_json_object_size, size_t, (const json_t *json), (json));
+DEF_FCN (nm_json_string, json_t *, (const char *value), (value));
+DEF_FCN (nm_json_string_value, const char *, (const json_t *json), (json));
+DEF_FCN (nm_json_true, json_t *, (void), ());
diff --git a/libnm-core/nm-json.h b/libnm-core/nm-json.h
index d857fe0275..2d0f10773d 100644
--- a/libnm-core/nm-json.h
+++ b/libnm-core/nm-json.h
@@ -6,34 +6,95 @@
#ifndef __NM_JSON_H__
#define __NM_JSON_H__
-gboolean nm_jansson_load (void);
-
-#ifndef NM_JANSSON_C
-#define json_object_iter_value (*_nm_jansson_json_object_iter_value)
-#define json_object_key_to_iter (*_nm_jansson_json_object_key_to_iter)
-#define json_integer (*_nm_jansson_json_integer)
-#define json_object_del (*_nm_jansson_json_object_del)
-#define json_array_get (*_nm_jansson_json_array_get)
-#define json_array_size (*_nm_jansson_json_array_size)
-#define json_array_append_new (*_nm_jansson_json_array_append_new)
-#define json_string (*_nm_jansson_json_string)
-#define json_object_iter_next (*_nm_jansson_json_object_iter_next)
-#define json_loads (*_nm_jansson_json_loads)
-#define json_dumps (*_nm_jansson_json_dumps)
-#define json_object_iter_key (*_nm_jansson_json_object_iter_key)
-#define json_object (*_nm_jansson_json_object)
-#define json_object_get (*_nm_jansson_json_object_get)
-#define json_array (*_nm_jansson_json_array)
-#define json_false (*_nm_jansson_json_false)
-#define json_delete (*_nm_jansson_json_delete)
-#define json_true (*_nm_jansson_json_true)
-#define json_object_size (*_nm_jansson_json_object_size)
-#define json_object_set_new (*_nm_jansson_json_object_set_new)
-#define json_object_iter (*_nm_jansson_json_object_iter)
-#define json_integer_value (*_nm_jansson_json_integer_value)
-#define json_string_value (*_nm_jansson_json_string_value)
+#define json_array nm_json_array
+#define json_array_append_new nm_json_array_append_new
+#define json_array_get nm_json_array_get
+#define json_array_size nm_json_array_size
+#define json_delete nm_json_delete
+#define json_dumps nm_json_dumps
+#define json_false nm_json_false
+#define json_integer nm_json_integer
+#define json_integer_value nm_json_integer_value
+#define json_loads nm_json_loads
+#define json_object nm_json_object
+#define json_object_del nm_json_object_del
+#define json_object_get nm_json_object_get
+#define json_object_iter nm_json_object_iter
+#define json_object_iter_key nm_json_object_iter_key
+#define json_object_iter_next nm_json_object_iter_next
+#define json_object_iter_value nm_json_object_iter_value
+#define json_object_key_to_iter nm_json_object_key_to_iter
+#define json_object_set_new nm_json_object_set_new
+#define json_object_size nm_json_object_size
+#define json_string nm_json_string
+#define json_string_value nm_json_string_value
+#define json_true nm_json_true
#include "nm-glib-aux/nm-jansson.h"
-#endif
+
+typedef struct {
+ gboolean loaded;
+ char *(*nm_json_dumps) (const json_t *json, size_t flags);
+ const char *(*nm_json_object_iter_key) (void *iter);
+ const char *(*nm_json_string_value) (const json_t *json);
+ int (*nm_json_array_append_new) (json_t *json, json_t *value);
+ int (*nm_json_object_del) (json_t *json, const char *key);
+ int (*nm_json_object_set_new) (json_t *json, const char *key, json_t *value);
+ json_int_t (*nm_json_integer_value) (const json_t *json);
+ json_t *(*nm_json_array) (void);
+ json_t *(*nm_json_array_get) (const json_t *json, size_t index);
+ json_t *(*nm_json_false) (void);
+ json_t *(*nm_json_integer) (json_int_t value);
+ json_t *(*nm_json_loads) (const char *string, size_t flags, json_error_t *error);
+ json_t *(*nm_json_object) (void);
+ json_t *(*nm_json_object_get) (const json_t *json, const char *key);
+ json_t *(*nm_json_object_iter_value) (void *);
+ json_t *(*nm_json_string) (const char *value);
+ json_t *(*nm_json_true) (void);
+ size_t (*nm_json_array_size) (const json_t *json);
+ size_t (*nm_json_object_size) (const json_t *json);
+ void (*nm_json_delete) (json_t *json);
+ void *(*nm_json_object_iter) (json_t *json);
+ void *(*nm_json_object_iter_next) (json_t *json, void *iter);
+ void *(*nm_json_object_key_to_iter) (const char *key);
+} NMJsonVt;
+
+extern const NMJsonVt *_nm_json_vt_ptr;
+
+const NMJsonVt *_nm_json_vt_init (void);
+
+static inline const NMJsonVt *
+_nm_json_vt (void)
+{
+ const NMJsonVt *vt;
+
+ vt = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr);
+ if (G_UNLIKELY (!vt)) {
+ vt = _nm_json_vt_init ();
+ nm_assert (vt);
+ }
+ return vt;
+}
+
+static inline const NMJsonVt *
+nm_json_vt (void)
+{
+ const NMJsonVt *vt;
+
+ vt = _nm_json_vt();
+ return vt->loaded ? vt : NULL;
+}
+
+static inline const NMJsonVt *
+nm_json_vt_assert (void)
+{
+ const NMJsonVt *vt;
+
+ vt = _nm_json_vt();
+ nm_assert (vt->loaded);
+ return vt;
+}
+
+const NMJsonVt *nmtst_json_vt_reset (gboolean loaded);
#endif /* __NM_JSON_H__ */
diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c
index 084547c8f8..af96b995d7 100644
--- a/libnm-core/nm-team-utils.c
+++ b/libnm-core/nm-team-utils.c
@@ -1870,7 +1870,7 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str)
{
nm_auto_decref_json json_t *root_js_obj = NULL;
- if (nm_jansson_load ())
+ if (nm_json_vt ())
root_js_obj = json_loads (js_str, 0, NULL);
if ( !root_js_obj
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 4127abb54d..b7b54948b4 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -5507,7 +5507,7 @@ nm_utils_is_json_object (const char *str, GError **error)
return FALSE;
}
- if (!nm_jansson_load ())
+ if (!nm_json_vt ())
return _nm_utils_is_json_object_no_validation (str, error);
json = json_loads (str, JSON_REJECT_DUPLICATES, &jerror);