NetworkManager/libnm-core/nm-json.c
Thomas Haller 7df0229c62
libnm: don't include <jansson.h> in libnm but use own variants
It's error prone to include the header and trying not to use it.
Don't include <jansson.h>. Instead, redefine our nm variants of
everything.

Note that we only redefine stuff that is in public headers (like
"json_t" typedef). libjansson anyway must not change the struct layout
and the like, without breaking all applications. That is because the
non-opaque code from the header anyway is part of the applications that
include it. Later we will add additional unit test that checks that our
redefinition matches to what we had at compile time.
2020-07-09 11:47:05 +02:00

134 lines
2.9 KiB
C

// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2017, 2018 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-json.h"
#include <dlfcn.h>
typedef struct {
NMJsonVt vt;
void *dl_handle;
} NMJsonVtInternal;
static NMJsonVtInternal *
_nm_json_vt_internal_load (void)
{
NMJsonVtInternal *v;
void *handle = NULL;
int mode;
v = g_new0 (NMJsonVtInternal, 1);
#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
if (strlen (JANSSON_SONAME) > 0)
handle = dlopen (JANSSON_SONAME, mode);
if (!handle)
return v;
#define TRY_BIND_SYMBOL(symbol) \
G_STMT_START { \
void *_sym = dlsym (handle, #symbol); \
\
if (!_sym) \
goto fail_symbol; \
v->vt.nm_ ## symbol = _sym; \
} G_STMT_END
TRY_BIND_SYMBOL (json_array);
TRY_BIND_SYMBOL (json_array_append_new);
TRY_BIND_SYMBOL (json_array_get);
TRY_BIND_SYMBOL (json_array_size);
TRY_BIND_SYMBOL (json_delete);
TRY_BIND_SYMBOL (json_dumps);
TRY_BIND_SYMBOL (json_false);
TRY_BIND_SYMBOL (json_integer);
TRY_BIND_SYMBOL (json_integer_value);
TRY_BIND_SYMBOL (json_loads);
TRY_BIND_SYMBOL (json_object);
TRY_BIND_SYMBOL (json_object_del);
TRY_BIND_SYMBOL (json_object_get);
TRY_BIND_SYMBOL (json_object_iter);
TRY_BIND_SYMBOL (json_object_iter_key);
TRY_BIND_SYMBOL (json_object_iter_next);
TRY_BIND_SYMBOL (json_object_iter_value);
TRY_BIND_SYMBOL (json_object_key_to_iter);
TRY_BIND_SYMBOL (json_object_set_new);
TRY_BIND_SYMBOL (json_object_size);
TRY_BIND_SYMBOL (json_string);
TRY_BIND_SYMBOL (json_string_value);
TRY_BIND_SYMBOL (json_true);
v->vt.loaded = TRUE;
v->dl_handle = handle;
return v;
fail_symbol:
dlclose (&handle);
*v = (NMJsonVtInternal) { };
return v;
}
const NMJsonVt *_nm_json_vt_ptr = NULL;
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;
}