From a0f8774a702394c4912cba65e47d1165154a041a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 4 Aug 2023 12:47:47 +0100 Subject: [PATCH] Get uninstalled libraries from environment in preference to ELF headers Introspecting the dynamic headers is low-level and full of implementation details. It seems that gnome-shell was assuming the address of the string table is given by taking the DT_STRTAB dynamic symbol table's value (d_un.d_val) and casting it to an absolute pointer. However, in some environments (apparently including Debian mips64el) the DT_STRTAB dynamic symbol table's d_un.d_val can be merely an offset relative to the base address of the executable in memory. The base address would have to be parsed from a different ELF header, which as far as I know is not part of _DYNAMIC. Rather than trying to look up the Shell executable's base address using dlinfo() or similar, during unit testing it seems easier to pass in the uninstalled library search path in the environment, along with other uninstalled paths that we are going to need anyway. The reason given for not using GI_TYPELIB_PATH in commit 9bc89b82 "main: Prepend RPATH or RUNPATH paths to gir search paths" was that g_irepository_prepend_library_path() takes precedence, but we can easily define our own environment variable that takes even higher precedence. If it's set, we might as well also bypass the PKGLIBDIR, since while running uninstalled we *only* want to use the uninstalled libraries. When not running unit tests, it's desirable to make `./build/src/gnome-shell` something you can run directly, so continue to parse the ELF headers - but only on x86_64, where we're reasonably confident that it works and any regressions with a newer glibc will be noticed promptly. Resolves: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6877 Bug-Debian: https://bugs.debian.org/1042980 Signed-off-by: Simon McVittie --- src/main.c | 39 ++++++++++++++++++++++++++++++++------- tests/meson.build | 4 ++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index bbf845999..d63ec546b 100644 --- a/src/main.c +++ b/src/main.c @@ -129,10 +129,16 @@ shell_dbus_init (gboolean replace) g_object_unref (session); } -#ifdef HAVE_EXE_INTROSPECTION static void maybe_add_rpath_introspection_paths (void) { + /* We're reasonably confident that this works reliably on x86_64, but + * on other architectures it can go wrong: for example it seems that + * on mips*el, the DT_STRTAB is an offset relative to the base address + * of the executable, rather than a ready-to-use pointer. + * + * Other architectures can be added here, but please test them first. */ +#if defined(HAVE_EXE_INTROSPECTION) && defined(__x86_64__) ElfW (Dyn) *dyn; ElfW (Dyn) *rpath = NULL; ElfW (Dyn) *runpath = NULL; @@ -194,15 +200,15 @@ maybe_add_rpath_introspection_paths (void) g_irepository_prepend_search_path (rpath_dir->str); g_irepository_prepend_library_path (rpath_dir->str); } -} #endif /* HAVE_EXE_INTROSPECTION */ +} static void shell_introspection_init (void) { + const char *env; g_irepository_prepend_search_path (MUTTER_TYPELIB_DIR); - g_irepository_prepend_search_path (GNOME_SHELL_PKGLIBDIR); /* We need to explicitly add the directories where the private libraries are * installed to the GIR's library path, so that they can be found at runtime @@ -210,11 +216,30 @@ shell_introspection_init (void) * for some linkers (e.g. gold) and in some distros (e.g. Debian). */ g_irepository_prepend_library_path (MUTTER_TYPELIB_DIR); - g_irepository_prepend_library_path (GNOME_SHELL_PKGLIBDIR); -#ifdef HAVE_EXE_INTROSPECTION - maybe_add_rpath_introspection_paths (); -#endif + env = g_getenv ("GNOME_SHELL_TEST_LIBRARY_PATH"); + + if (env != NULL) + { + g_auto (GStrv) paths = NULL; + char **str; + + paths = g_strsplit (env, ":", -1); + + for (str = paths; *str; str++) + { + g_debug ("Prepending '%s' to introspection library search path", + *str); + g_irepository_prepend_search_path (*str); + g_irepository_prepend_library_path (*str); + } + } + else + { + g_irepository_prepend_search_path (GNOME_SHELL_PKGLIBDIR); + g_irepository_prepend_library_path (GNOME_SHELL_PKGLIBDIR); + maybe_add_rpath_introspection_paths (); + } } static void diff --git a/tests/meson.build b/tests/meson.build index df35080fe..6717d7958 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -61,6 +61,10 @@ shell_testenv.set('GNOME_SHELL_DATADIR', data_builddir) shell_testenv.set('GNOME_SHELL_BUILDDIR', src_builddir) shell_testenv.set('GNOME_SHELL_SESSION_MODE', 'user') shell_testenv.set('SHELL_BACKGROUND_IMAGE', '@0@'.format(background_file)) +shell_testenv.set('GNOME_SHELL_TEST_LIBRARY_PATH', ':'.join([ + src_builddir, + src_builddir / 'st', +])) shell_testenv.append('GI_TYPELIB_PATH', gvc_typelib_path, separator: ':') shell_testenv.append('LD_LIBRARY_PATH', libgvc_path, separator: ':')