loader: Use dlsym to get our udev symbols instead of explicit linking.
authorEric Anholt <eric@anholt.net>
Thu, 23 Jan 2014 21:12:26 +0000 (13:12 -0800)
committerEric Anholt <eric@anholt.net>
Mon, 27 Jan 2014 17:36:24 +0000 (09:36 -0800)
Steam links against libudev.so.0, while we're linking against
libudev.so.1.  The result is that the symbol names (which are the same in
the two libraries) end up conflicting, and some of the usage of .so.1
calls the .so.0 bits, which have different internal structures, and
segfaults happen.

By using a dlopen() with RTLD_LOCAL, we can explicitly look for the
symbols we want, while they get the symbols they want.

Reviewed-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Kristian Høgsberg <krh@bitplanet.net>
Tested-by: Alexandre Demers <alexandre.f.demers@gmail.com>
Tested-by: Mike Lothian <mike@fireburn.co.uk>
configure.ac
src/egl/main/Makefile.am
src/loader/Makefile.am
src/loader/loader.c

index 33ac92259485ffdbd572f1d1d515f4b0912d2eda..d266d96b67478c8b86498d2851a925b0ecd774c9 100644 (file)
@@ -858,7 +858,7 @@ xyesno)
 
     if test x"$enable_dri3$have_libudev" = xyesyes; then
         X11_INCLUDES="$X11_INCLUDES $LIBUDEV_CFLAGS"
-        GL_LIB_DEPS="$GL_LIB_DEPS $LIBUDEV_LIBS"
+        GL_LIB_DEPS="$GL_LIB_DEPS"
     fi
 
     # need DRM libs, $PTHREAD_LIBS, etc.
index 60cb6006b509178ef8b472605ca54d3d5b1f5709..e12aeae59b9161bcd257cba9836b6c52274bc810 100644 (file)
@@ -112,7 +112,7 @@ if HAVE_EGL_DRIVER_DRI2
 AM_CFLAGS += -D_EGL_BUILT_IN_DRIVER_DRI2
 AM_CFLAGS += -DHAVE_XCB_DRI2
 libEGL_la_LIBADD += ../drivers/dri2/libegl_dri2.la
-libEGL_la_LIBADD += $(LIBUDEV_LIBS) $(DLOPEN_LIBS) $(LIBDRM_LIBS)
+libEGL_la_LIBADD += $(DLOPEN_LIBS) $(LIBDRM_LIBS)
 endif
 
 # Provide compatibility with scripts for the old Mesa build system for
index 371dd575c095c7ee59730b89ac3d14d119a0a213..bddf7ac35ed7db741f9058be1fc1a96411117e9f 100644 (file)
@@ -29,9 +29,6 @@ libloader_la_CPPFLAGS = \
        $(VISIBILITY_CFLAGS) \
        $(LIBUDEV_CFLAGS)
 
-libloader_la_LIBADD = \
-       $(LIBUDEV_LIBS)
-
 if !HAVE_LIBDRM
 libloader_la_CPPFLAGS += \
        -D__NOT_HAVE_DRM_H
@@ -39,7 +36,7 @@ else
 libloader_la_CPPFLAGS += \
        $(LIBDRM_CFLAGS)
 
-libloader_la_LIBADD += \
+libloader_la_LIBADD = \
        $(LIBDRM_LIBS)
 endif
 
index a5bd7692e6e716573a26ca27fd19d421bafc763b..63b977aa7434664acb3479b97a71b52cf4381864 100644 (file)
@@ -67,6 +67,8 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
 #include "loader.h"
 
 #ifndef __NOT_HAVE_DRM_H
@@ -92,11 +94,37 @@ static void (*log_)(int level, const char *fmt, ...) = default_logger;
 #ifdef HAVE_LIBUDEV
 #include <libudev.h>
 
+static void *udev_handle = NULL;
+
+static void *
+udev_dlopen_handle(void)
+{
+   if (!udev_handle) {
+      udev_handle = dlopen("libudev.so.1", RTLD_LOCAL | RTLD_LAZY);
+   }
+
+   return udev_handle;
+}
+
+static void *
+asserted_dlsym(void *dlopen_handle, const char *name)
+{
+   void *result = dlsym(dlopen_handle, name);
+   assert(result);
+   return result;
+}
+
+#define UDEV_SYMBOL(ret, name, args) \
+   ret (*name) args = asserted_dlsym(udev_dlopen_handle(), #name);
+
+
 static inline struct udev_device *
 udev_device_new_from_fd(struct udev *udev, int fd)
 {
    struct udev_device *device;
    struct stat buf;
+   UDEV_SYMBOL(struct udev_device *, udev_device_new_from_devnum,
+               (struct udev *udev, char type, dev_t devnum));
 
    if (fstat(fd, &buf) < 0) {
       log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d", fd);
@@ -119,6 +147,14 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
    struct udev *udev = NULL;
    struct udev_device *device = NULL, *parent;
    const char *pci_id;
+   UDEV_SYMBOL(struct udev *, udev_new, (void));
+   UDEV_SYMBOL(struct udev_device *, udev_device_get_parent,
+               (struct udev_device *));
+   UDEV_SYMBOL(const char *, udev_device_get_property_value,
+               (struct udev_device *, const char *));
+   UDEV_SYMBOL(struct udev_device *, udev_device_unref,
+               (struct udev_device *));
+   UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *));
 
    *chip_id = -1;
 
@@ -240,6 +276,12 @@ loader_get_device_name_for_fd(int fd)
    struct udev *udev;
    struct udev_device *device;
    const char *const_device_name;
+   UDEV_SYMBOL(struct udev *, udev_new, (void));
+   UDEV_SYMBOL(const char *, udev_device_get_devnode,
+               (struct udev_device *));
+   UDEV_SYMBOL(struct udev_device *, udev_device_unref,
+               (struct udev_device *));
+   UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *));
 
    udev = udev_new();
    device = udev_device_new_from_fd(udev, fd);