On Tue, Jul 31, 2018 at 03:55:28PM +0100, Daniel P. Berrangé wrote:
The jansson and json-glib libraries both export symbols with a json_
name prefix and json_object_iter_next() clashes between them.
Unfortunately json_glib is linked in by GTK, so any app using GTK and
json-glib
libvirt will get a clash, resulting in SEGV. This also affects the
NSS
module provided by libvirt
Instead of directly linking to jansson, use dlopen() with the RTLD_LOCAL
flag which allows us to hide the symbols from the application that loads
libvirt or the NSS module.
Some preprocessor black magic and wrapper functions are used to redirect
calls into the dlopen resolved symbols.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
libvirt.spec.in | 2 +
src/Makefile.am | 3 +
src/util/Makefile.inc.am | 3 +-
src/util/virjson.c | 9 +-
src/util/virjsoncompat.c | 253 +++++++++++++++++++++++++++++++++++++++
src/util/virjsoncompat.h | 86 +++++++++++++
6 files changed, 354 insertions(+), 2 deletions(-)
create mode 100644 src/util/virjsoncompat.c
create mode 100644 src/util/virjsoncompat.h
diff --git a/src/util/virjsoncompat.c b/src/util/virjsoncompat.c
new file mode 100644
index 0000000000..c317e50c32
--- /dev/null
+++ b/src/util/virjsoncompat.c
@@ -0,0 +1,253 @@
+/*
+ * virjsoncompat.c: JSON object parsing/formatting
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virthread.h"
+#include "virerror.h"
+#define VIR_JSON_COMPAT_IMPL
+#include "virjsoncompat.h"
virjsoncompat.h includes jansson.h unconditionally, so this fails to
compile on a machine without jansson-devel:
In file included from util/virjsoncompat.c:27:
util/virjsoncompat.h:56:10: fatal error: jansson.h: No such file or directory
#include <jansson.h>
^~~~~~~~~~~
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#if WITH_JANSSON
+
+#include <dlfcn.h>
+
+json_t *(*json_array_ptr)(void);
+int (*json_array_append_new_ptr)(json_t *array, json_t *value);
+json_t *(*json_array_get_ptr)(const json_t *array, size_t index);
+size_t (*json_array_size_ptr)(const json_t *array);
+void (*json_delete_ptr)(json_t *json);
+char *(*json_dumps_ptr)(const json_t *json, size_t flags);
+json_t *(*json_false_ptr)(void);
+json_t *(*json_integer_ptr)(json_int_t value);
+json_int_t (*json_integer_value_ptr)(const json_t *integer);
+json_t *(*json_loads_ptr)(const char *input, size_t flags, json_error_t *error);
+json_t *(*json_null_ptr)(void);
+json_t *(*json_object_ptr)(void);
+void *(*json_object_iter_ptr)(json_t *object);
+const char *(*json_object_iter_key_ptr)(void *iter);
+void *(*json_object_iter_next_ptr)(json_t *object, void *iter);
+json_t *(*json_object_iter_value_ptr)(void *iter);
+void *(*json_object_key_to_iter_ptr)(const char *key);
+int (*json_object_set_new_ptr)(json_t *object, const char *key, json_t *value);
+json_t *(*json_real_ptr)(double value);
+double (*json_real_value_ptr)(const json_t *real);
+json_t *(*json_string_ptr)(const char *value);
+const char *(*json_string_value_ptr)(const json_t *string);
+json_t *(*json_true_ptr)(void);
+
+
+static int virJSONJanssonOnceInit(void)
+{
+ void *handle = dlopen("libjansson.so.4",
RTLD_LAZY|RTLD_LOCAL|RTLD_DEEPBIND|RTLD_NODELETE);
+ if (!handle) {
+ virReportError(VIR_ERR_NO_SUPPORT,
+ _("libjansson.so.4 JSON library not available: %s"),
dlerror());
+ return -1;
+ }
+
+#define LOAD(name) \
+ do { \
+ if (!(name ## _ptr = dlsym(handle, #name))) { \
+ virReportError(VIR_ERR_NO_SUPPORT, \
+ _("missing symbol '%s' in libjansson.so.4:
%s"), #name, dlerror()); \
+ goto error; \
If you do
return -1;
you can drop the error label.
+ } \
+ fprintf(stderr, "Resolve %s to %p\n", #name, name ## _ptr); \
+ } while (0)
+
+ LOAD(json_array);
+ LOAD(json_array_append_new);
+ LOAD(json_array_get);
+ LOAD(json_array_size);
+ LOAD(json_delete);
+ LOAD(json_dumps);
+ LOAD(json_false);
+ LOAD(json_integer);
+ LOAD(json_integer_value);
+ LOAD(json_loads);
+ LOAD(json_null);
+ LOAD(json_object);
+ LOAD(json_object_iter);
+ LOAD(json_object_iter_key);
+ LOAD(json_object_iter_next);
+ LOAD(json_object_iter_value);
+ LOAD(json_object_key_to_iter);
+ LOAD(json_object_set_new);
+ LOAD(json_real);
+ LOAD(json_real_value);
+ LOAD(json_string);
+ LOAD(json_string_value);
+ LOAD(json_true);
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+VIR_ONCE_GLOBAL_INIT(virJSONJansson);
[...]
+
+#endif
+
Extra newline at EOF.
With the conditional include of jansson.h:
Reviewed-by: Ján Tomko <jtomko(a)redhat.com>
Thanks for the magic.
Jano