tech-x11 archive

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

Re: alacritty: possible inputmethod issue?



tnn reports that this works when built with X from pkgsrc, so I wonder
if we're doing something wrong in base X11 to break this.

Does anyone have an idea?

This is caused by:

1. alacritty -> dlopen(libX11.so)
2. libX11.so -> dlopen(/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so)
3. xlcUTF8Load.so referencing _XlcGenericMethods back inside libX11.so

---
$ LD_LIBRARY_PATH=/usr/src/external/mit/xorg/lib/libX11/dynamic/ ./xim-dl
Trying to open XIM without RTLD_GLOBAL
path=/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2
/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2: Undefined symbol "_XlcGenericMethods" (symnum = 7)
path=/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2
/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2: Undefined symbol "_XlcGenericMethods" (symnum = 7)
path=/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2
/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2: Undefined symbol "_XlcGenericMethods" (symnum = 7)
path=/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2
/usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so.2: Undefined symbol "_XlcGenericMethods" (symnum = 7)
XSetLocaleModifiers() failed
[...]

$ nm -D /usr/X11R7/lib/libX11.so | fgrep _XlcGenericMethods
0000000000305040 D _XlcGenericMethods
$ nm -D /usr/X11R7/lib/X11/locale/lib/common/xlcDef.so | fgrep _XlcGenericMethods
                 U _XlcGenericMethods
$ nm -D /usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so | fgrep _XlcGenericMethods
                 U _XlcGenericMethods
$ nm -D /usr/X11R7/lib/X11/locale/lib/common/xlibi18n.so | fgrep _XlcGenericMethods
                 U _XlcGenericMethods

---

None of the runtime linkers that I tried (NetBSD 9.99.86, FreeBSD 13-RELEASE, Ubuntu 19.04) allow this sort of "back-reference" without
RTLD_GLOBAL (possibly to preclude reference-loops).

The solution is to either
a) fold these locale modules back into libX11.so like in pkgsrc:

---
# pkgsrc
$ nm -D lib/libX11.so.6.4.0 | fgrep _XlcUtf8Loader
000000000006efe0 T _XlcUtf8Loader
$

# system xorg
$ nm -D /usr/X11R7/lib/libX11.so | fgrep _XlcUtf8Loader
$ nm -D /usr/X11R7/lib/X11/locale/lib/common/xlcUTF8Load.so |
  fgrep _XlcUtf8Loader
0000000000000760 T _XlcUtf8Loader
$
---

or,

b) Explicitly link the locale modules with -lX11: after all they
   are using stuff from there. Right now, they only depend on
   libc.so

Test programs (many thanks to iquiw--I wouldn't have bothered to
look into this without xim-dl.c):

---
==> Makefile <==
CC = gcc
CFLAGS = -Wall -Wextra -O2 -pipe
LFLAGS = -fpic -shared

run: dltest
	env LD_LIBRARY_PATH=$$(pwd) ./dltest

dltest: main.c a.so b.so
	${CC} ${CFLAGS} -o $@ main.c

a.so: a.c
	${CC} ${CFLAGS} ${LFLAGS} -o $@ $>

b.so: b.c
	${CC} ${CFLAGS} ${LFLAGS} -o $@ $>

clean:
	rm -f dltest *.so

==> a.c <==
#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>

int a;

bool
a_fn(void)
{
	bool (*b_fn)(void);
	void* h;

	printf("Inside: %s\n", __func__);
	a = 42;	/* no access from dlopen()ed b.so */

	if ((h = dlopen("b.so", RTLD_NOW)) == NULL) {
		fprintf(stderr, "%s\n", dlerror());
		return false;
	}

	if ((b_fn = (bool (*)(void))dlsym(h, "b_fn")) == NULL) {
		fprintf(stderr, "%s\n", dlerror());
		dlclose(h);
		return false;
	}

	dlclose(h);
	return true;
}

==> b.c <==
#include <stdbool.h>
#include <stdio.h>

extern int a;

bool
b_fn(void)
{
	printf("Inside: %s\n", __func__);
	printf("Extern: a=%d\n", a);

	return true;
}

==> main.c <==
/**
 * https://mail-index.netbsd.org/tech-x11/2021/06/19/msg002208.html
 *
 * main() loads a.so; calls a_fn() within
 * a_fn() defines global int a; tries to load b.so
 * Without RTLD_GLOBAL this load will fail because of back-referenced
 * symbol `a' in b.so. Only forward-references are OK for the runtime
 * linker.
 *
 * alacritty, written in Rust, fails to start on NetBSD because of this
 * behaviour. alacritty -> libX11.so -> xlcUTF8load.so -> which needs
 * _XlcGenericMethods defined in libX11.so.
 */

#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>

static void
my_dl(int flags)
{
	bool (*a_fn)(void);
	void* h;

	if ((h = dlopen("a.so", flags)) == NULL)
		fprintf(stderr, "%s\n", dlerror());
	else {
		if ((a_fn = (bool (*)(void))dlsym(h, "a_fn")) == NULL)
			fprintf(stderr, "%s\n", dlerror());
		else
			printf("a_fn loading b.so = %s\n", a_fn() ?
				"OK" : "ERR");
		dlclose(h);
	}
}

int
main(void)
{
	printf("loading a.so with RTLD_NOW\n");
	my_dl(RTLD_NOW);

	printf("loading a.so with RTLD_NOW | RTLD_GLOBAL\n");
	my_dl(RTLD_NOW | RTLD_GLOBAL);

	return 0;
}
---

-RVP


Home | Main Index | Thread Index | Old Index