Allow dlopen of plugins to fail

It happens with some frequency that plugins that might be unimportant to
the evaluation at hand mismatch with the nix version, leading to
spurious load failures. Let's make these non fatal.

Change-Id: Iba10e951d171725ccf1a121bcd9be1e1d6ad69eb
This commit is contained in:
jade 2024-03-11 00:50:57 -07:00
parent 7d361f1a82
commit 0d85875c3a
6 changed files with 48 additions and 4 deletions

View file

@ -342,7 +342,7 @@ void initPlugins()
void *handle = void *handle =
dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL); dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) if (!handle)
throw Error("could not dynamically open plugin file '%s': %s", file, dlerror()); warn("could not dynamically open plugin file '%s': %s", file, dlerror());
} }
} }

View file

@ -141,7 +141,8 @@ endif
$(d)/test-libstoreconsumer.sh.test $(d)/test-libstoreconsumer.sh.test-debug: \ $(d)/test-libstoreconsumer.sh.test $(d)/test-libstoreconsumer.sh.test-debug: \
$(buildprefix)$(d)/test-libstoreconsumer/test-libstoreconsumer $(buildprefix)$(d)/test-libstoreconsumer/test-libstoreconsumer
$(d)/plugins.sh.test $(d)/plugins.sh.test-debug: \ $(d)/plugins.sh.test $(d)/plugins.sh.test-debug: \
$(buildprefix)$(d)/plugins/libplugintest.$(SO_EXT) $(buildprefix)$(d)/plugins/libplugintest.$(SO_EXT) \
$(buildprefix)$(d)/plugins/libplugintestfail.$(SO_EXT)
$(d)/test-repl-characterization.sh.test $(d)/test-repl-characterization.sh.test-debug: \ $(d)/test-repl-characterization.sh.test $(d)/test-repl-characterization.sh.test-debug: \
$(buildprefix)$(d)/repl_characterization/test-repl-characterization $(buildprefix)$(d)/repl_characterization/test-repl-characterization

View file

@ -4,6 +4,20 @@ if [[ $BUILD_SHARED_LIBS != 1 ]]; then
skipTest "Plugins are not supported" skipTest "Plugins are not supported"
fi fi
res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest* eval --expr builtins.anotherNull) res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest.* eval --expr builtins.anotherNull)
[ "$res"x = "nullx" ] [ "$res"x = "nullx" ]
# Plugin load failing due to missing symbols
res=$(nix --option plugin-files $PWD/plugins/libplugintestfail.* eval --expr '1234 + 5' 2>&1)
# We expect this to succeed evaluating
echo "$res" | grep 1239 >/dev/null
# On Linux, we expect this to print some failure of dlopen.
# Only on Linux do we expect for sure that -z now is set on the .so file, so it
# will definitely fail to load instead of lazy loading (and thus not hitting
# the missing symbol).
# FIXME(jade): does there exist an equivalent of -z now on macOS that eluded us
# in search?
if [[ "$(uname -s)" == Linux ]]; then
echo "$res" | grep "could not dynamically open plugin file" >/dev/null
fi

View file

@ -1,4 +1,4 @@
libraries += libplugintest libraries += libplugintest libplugintestfail
libplugintest_DIR := $(d) libplugintest_DIR := $(d)
@ -9,3 +9,19 @@ libplugintest_ALLOW_UNDEFINED := 1
libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1 libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1
libplugintest_CXXFLAGS := -I src/libutil -I src/libstore -I src/libexpr -I src/libfetchers libplugintest_CXXFLAGS := -I src/libutil -I src/libstore -I src/libexpr -I src/libfetchers
libplugintestfail_DIR := $(d)
libplugintestfail_SOURCES := $(d)/plugintestfail.cc
libplugintestfail_ALLOW_UNDEFINED := 1
libplugintestfail_EXCLUDE_FROM_LIBRARY_LIST := 1
libplugintestfail_CXXFLAGS := -I src/libutil -I src/libstore -I src/libexpr -I src/libfetchers -DMISSING_REFERENCE
# Make sure that the linker strictly evaluates all symbols on .so load on Linux
# so it will definitely fail to load as expected.
ifdef HOST_LINUX
libplugintestfail_LDFLAGS += -z now
endif

View file

@ -1,8 +1,15 @@
#include "config.hh" #include "config.hh"
#include "primops.hh" #include "primops.hh"
#include <stdlib.h>
using namespace nix; using namespace nix;
#ifdef MISSING_REFERENCE
extern void meow();
#else
#define meow() {}
#endif
struct MySettings : Config struct MySettings : Config
{ {
Setting<bool> settingSet{this, false, "setting-set", Setting<bool> settingSet{this, false, "setting-set",
@ -13,6 +20,11 @@ MySettings mySettings;
static GlobalConfig::Register rs(&mySettings); static GlobalConfig::Register rs(&mySettings);
[[gnu::used, gnu::unused, gnu::retain]]
static void maybeRequireMeowForDlopen() {
meow();
}
static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v) static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v)
{ {
if (mySettings.settingSet) if (mySettings.settingSet)

View file

@ -0,0 +1 @@
plugintest.cc