lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


A coworker was working on a Perl module and ran into the issue of require
ultimately using RTLD_LOCAL by default. Perl modules subsequently loaded
would cause a segfault because libperl, as linked in by the Lua Perl module,
was not visible. 

The obvious solution was to use loadlib for Lua 5.2, but we were using Lua
5.1. On Lua 5.1 the typical solution is to use an alternate binding to
dlopen which allows you to specify load flags, but then you have to deal
with the logic of search paths, etc.

I found a concise hack using dladdr which allowed the Lua Perl module to
remain completely self-contained and keep user code blissfully ignorant of
linking details. This is not strictly portable, but works on Linux, OS X,
and probably anywhere dladdr(3) exists, which is nearly as common as
dlopen(3) itself.

Here's the relevant snippet which implements the hack:

	int luaopen_luaperl (lua_State *L) {
	        Dl_info info;

	        if (!dladdr(&luaopen_luaperl, &info)
		||  !info.dli_fname
	        ||  !dlopen(info.dli_fname, RTLD_GLOBAL|RTLD_NOW)) {
	                return luaL_error(L, "unable to export symbols");
	        }

It uses dladdr to derive its own path, then reopens itself with dlopen using
the RTLD_GLOBAL flag. All is right again with the universe.

One potential gotcha is that this breaks module unloading. Because the
second dlopen increments a reference count on the module, when Lua garbage
collects the module and calls dlclose there'll still be a reference. Most
people don't rely on module unloading, fortunately. Calling dlcose() on the
handle immediately after dlopen() might resolve this issue, but I haven't
tested it yet.