<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - lld: --no-allow-shlib-undefined: Doesn't check recursively"
   href="https://bugs.llvm.org/show_bug.cgi?id=52432">52432</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>lld: --no-allow-shlib-undefined: Doesn't check recursively
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lld
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>13.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>ELF
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>alx.manpages@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, smithp352@googlemail.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Original bug report (Debian):
<<a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=998687">https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=998687</a>>

Dear maintainers,

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

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
<span class="quote">>>> referenced by foo.c
>>>               foo.o:(foo_bar)</span >
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
$</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>