[llvm-bugs] [Bug 46676] New: Undefined symbol in dynamic library on the lld link line causes inaccurate symbol resolution

via llvm-bugs llvm-bugs at lists.llvm.org
Fri Jul 10 12:00:56 PDT 2020


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

            Bug ID: 46676
           Summary: Undefined symbol in dynamic library on the lld link
                    line causes inaccurate symbol resolution
           Product: lld
           Version: unspecified
          Hardware: PC
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: andrew.c.morrow at gmail.com
                CC: llvm-bugs at lists.llvm.org, smithp352 at googlemail.com

Created attachment 23718
  --> https://bugs.llvm.org/attachment.cgi?id=23718&action=edit
Archive of repro from https://github.com/acmorrow/lld-shadowing-repro

I don't know for sure that this is a bug in lld. It could well be that what is
being attempted just isn't required to work the way I hope. However, it does
work with the BFD and gold linkers, so I'm reporting what appears to be at
least a divergence in lld's behavior from those two.

I have produced a minimal reproduction here:
https://github.com/acmorrow/lld-shadowing-repro. I've also attached a tgz
snapshot of the repo to this ticket. Please see the README for details on how
to run the reproduction. 

The setup is admittedly a little unusual, but this is reduced from a real world
solution that was working with ld.gold and ld.bfd, and I was surprised to find
that lld behaved differently.

The repro setup involves a program and three libraries, two of which are
dynamic and one of which is static.

The static library and one of the dynamic libraries have a symbol collision.
Unfortunately, in the real environment from which this reproduction is derived,
the names of these symbols are not easily changed. It is intended that only the
definition of the symbol from the shared library be used, however, the static
library must appear on the link line for all other libraries and programs.

To model this, the repro sets up the following libraries and dependencies:

- `libbad_symbol.a`: defines a symbol named `shadowed` which calls `abort` to
model failure.
- `libgood_symbol.so`: also defines a symbol named `shadowed`, and links to
`libbad_symbol.a`
- `libsymbol_wrapper.so`: links to both `libgood_symbol.so` and
`libbad_symbol.a`, and references `shadowed`.
- `libsymbol_user.so`: links to `libsymbol_wrapper.so` and `libbad_symbol.a`,
references only symbols defined in `libsymbol_wrapper.so`
- `main`: links to `libsymbol_user.so` and libbad_symbol.a, and only references
symbols defined in `libsymbol_user.so`.

Invoking the definition of `shadowed` from `libbad_symbol.a` when running
`main` is considered a failing result. And as currently described, all three
linkers will result in a failure, because the definition of `shadowed` from
`libbad_symbol.a` will be included in `libsymbol_user.so`, even though
`libsymbol_user` does not make use of the `shadowed` symbol.

I believe this happens because when linking `libsymbol_user.so` the linker sees
that `libsymbol_wrapper.so`, which is on the link line, has an undefined
reference to `shadowed`, and the linker sees that it can satisfy the symbol by
incorporating the definition available from `libbad_symbols.a`. So
`libsymbol_user.so` ends up with a definition of `shadowed`, and then
`libsymbol_wrapper.so` ends up using that definition at runtime.

Note that in the real world scenario which prompted this reproduction, we do
not have control over the build of `libbad_symbol.a`, nor can we avoid having
it on the link line of all of the other libraries.

We do however have control over the build process for `libgood_symbol.so`,
though not the ability to easily rename all of its symbols to avoid the
collision.

Our solution was to introduce a version script
(https://sourceware.org/binutils/docs/ld/VERSION.html#VERSION) for the build of
`libgood_symbols.so` that pulled the symbols in `libgood_symbols.so` into a
version node, and therefore would disambiguate them from those in
`libbad_symbols.a`.

This appears to work as expected with both ld.bfd and ld.gold. With the version
script applied, the `shadowed` symbol does not become defined in
`libsymbol_user.so`, and at runtime the version from `libgood_symbol.so` is
used as intended.

However, with lld, this does not seem to happen. The link of
`libsymbol_user.so` still causes a definition for `shadowed` to be pulled from
`libbad_symbol.a` and as a consequence we call the wrong symbol at runtime.

I'll be the first to admit that this is a somewhat rickety setup. However, the
symbol collision is not of our making, we are just trying to work around it as
best we can. The version script had seemed like a good way out of the problem.

The alternative solution would be, we think, to add `libgood_symbol.so` to the
link line of every other library or program which uses `libsymbol_wrapper.so`.
However, we would prefer not to need to do that, as we view the use of
`libgood_symbol.so` and the `shadowed` symbol to be an internal implementation
detail of `libsymbol_wrapper.so`. No libraries other than
`libsymbol_wrapper.so` need to be aware of `libgood_symbol.so` or `shadowed`,
but there are many many libraries and programs that need to link to
`libsymbol_wrapper.so`. Needing reiterate `libgood_symbol.so` everywhere
`libsymbol_wrapper.so` gets used is fragile.

One final detail: my local experiments with this have shown that we observe
this issue on Ubuntu 18.04 with the system provided lld-7, lld-8, lld-9, and
lld-10 packages, but not with lld-6.0.

-- 
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/20200710/25fdd9d2/attachment.html>


More information about the llvm-bugs mailing list