[llvm-bugs] [Bug 52432] New: lld: --no-allow-shlib-undefined: Doesn't check recursively

via llvm-bugs llvm-bugs at lists.llvm.org
Sat Nov 6 06:29:25 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=52432

            Bug ID: 52432
           Summary: lld: --no-allow-shlib-undefined: Doesn't check
                    recursively
           Product: lld
           Version: 13.0
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: alx.manpages at gmail.com
                CC: llvm-bugs at lists.llvm.org, smithp352 at googlemail.com

Original bug report (Debian):
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=998687>

Dear maintainers,

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=lld
$
$ 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=lld
ld.lld: error: undefined symbol: bar
>>> referenced by foo.c
>>>               foo.o:(foo_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=lld
$
$ 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=lld
ld.lld: error: ./libfoo.so: undefined reference to bar
[--no-allow-shlib-undefined]
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=lld
$
$ 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=lld
ld.lld: error: ./libfoo.so: undefined reference to bar
[--no-allow-shlib-undefined]
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=lld
$
$ # NOTE: bfd and lld behave differently here!
$ # lld 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=lld
$
$ LD_LIBRARY_PATH=. ./foobar
./foobar: symbol lookup error: ./libfoo.so: undefined symbol: bar
$
$ # NOTE: bfd and lld behave differently here!
$ # lld 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=lld
$
$ LD_LIBRARY_PATH=. ./foovar
$

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20211106/6b4c58af/attachment.html>


More information about the llvm-bugs mailing list