[libvirt] [PATCH] util: avoid symbol clash between json libraries

Ján Tomko jtomko at redhat.com
Tue Jul 31 16:07:20 UTC 2018


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 at 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 at redhat.com>

Thanks for the magic.

Jano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20180731/8787e613/attachment-0001.sig>


More information about the libvir-list mailing list