Bug#998687: lld: --no-allow-shlib-undefined: Doesn't check recursively

Alejandro Colomar alx.manpages at gmail.com
Sat Nov 6 13:00:05 GMT 2021


Package: lld
Version: 1:13.0-53~exp1
Severity: normal
Tags: upstream
X-Debbugs-Cc: alx.manpages at gmail.com, Michael Kerrisk (man-pages) <mtk.manpages at gmail.com>, Diego Elio Pettenò <flameeyes at flameeyes.com>, 997999 at bugs.debian.org

Dear Maintainer,

A week ago I detected a bug in ld.gold, where it differs from ld.bfd:
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=997999>.

In the meantime, I've known about ld.lld, and wondered its behavior
regarding --no-allow-shlib-undefined.  After some experiment, it's
the same buggy behavior that ld.gold has, and differs from ld.bfd.

I would expect --no-allow-shlib-undefined to search recursively through
all of my dependencies and check if any of them has undefined symbols,
and report an error if so.  ld.bfd has that behavior.

Instead, ld.lld (and ld.gold) only check that my direct dependencies
have their symbols resolved, but they do not check the dependencies
of my dependencies.

That creates the possibility that an unmet dependency will cause a run-time
error, as I show in the example below.

Commands to reproduce the bug:

$ ll
total 20
-rw-r--r-- 1 user user 29 Oct 28 11:47 bar.c
-rw-r--r-- 1 user user 60 Oct 28 13:47 foobar.c
-rw-r--r-- 1 user user 83 Oct 28 11:46 foo.c
-rw-r--r-- 1 user user 52 Oct 28 13:47 foovar.c
-rw-r--r-- 1 user user 56 Oct 28 13:31 main.c
$ 
$ cat bar.c
	int bar(void)
	{
		return 1;
	}
$ cat foo.c
	int bar(void);

	int foo(void)
	{
		return 1;
	}

	int foo_bar(void)
	{
		return bar();
	}
$ cat foobar.c
	int foo_bar(void);

	int foobar(void)
	{
		return foo_bar();
	}
$ cat foovar.c
	int foo(void);

	int foobar(void)
	{
		return foo();
	}
$ cat main.c
	int foobar(void);

	int main(void)
	{
		return foobar();
	}
$ 
$ cc -c -fpic -Wall -Wextra -Werror main.c foo.c bar.c foobar.c foovar.c
$ 
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libbar.so bar.o -fuse-ld=bfd
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libbar.so bar.o -fuse-ld=gold
$ 
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=bfd
/usr/bin/ld.bfd: foo.o: in function `foo_bar':
foo.c:(.text+0x10): undefined reference to `bar'
collect2: error: ld returned 1 exit status
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=gold
foo.o:foo.c:function foo_bar: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
$ 
$ cc -shared -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=bfd
$ cc -shared -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=gold
$ 
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=gold
./libfoo.so: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
$ 
$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=bfd
$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=gold
$ 
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=gold
./libfoo.so: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
$ 
$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=bfd
$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=gold
$
$ # NOTE: bfd and gold behave differently here!
$ # gold will produce a buggy binary!!
$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foobar -Wl,-rpath=. main.o -L. -lfoobar -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foobar -Wl,-rpath=. main.o -L. -lfoobar -fuse-ld=gold
$ 
$ LD_LIBRARY_PATH=. ./foobar 
./foobar: symbol lookup error: ./libfoo.so: undefined symbol: bar
$ 
$ # NOTE: bfd and gold behave differently here!
$ # gold will produce a binary that luckily works here,
$ # but might break inadvertently if a future libfoovar starts using foo_bar()!
$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foovar -Wl,-rpath=. main.o -L. -lfoovar -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foovar -Wl,-rpath=. main.o -L. -lfoovar -fuse-ld=gold
$ 
$ LD_LIBRARY_PATH=. ./foovar
$ 

-- System Information:
Debian Release: bookworm/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 5.14.0-3-amd64 (SMP w/12 CPU threads)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages lld depends on:
ii  lld-13  1:13.0.0-9~exp1

lld recommends no packages.

lld suggests no packages.

-- no debconf information


More information about the Pkg-llvm-team mailing list