Re: alacritty: possible inputmethod issue?

RVP <[email protected]> Mon, 12 Jul 2021 12:09:44 +0000 (UTC)
Newsgroups gmane.os.netbsd.devel.x11
Message-ID <[email protected]>
> 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