Repository: conda/conda-build

Issue:
Potential bug in pyldd - erraneous DT_NEEDED
<!--
Thanks for opening an issue! A few things to keep in mind:

- This issue tracker is for issues with or enhancements for conda-build.

For conda issues, you should open an issue at https://github.com/conda/conda/issues
For Anaconda issues, you should open an issue at https://github.com/ContinuumIO/anaconda-issues/issues
For an issue with a particular conda-forge package, you should open an issue on the 
corresponding feedstock: https://github.com/conda-forge
-->

### Actual Behavior

pyldd reports wrong contents of the DT_NEEDED section of one DSO.

### Expected Behavior

pyldd should report the correct contents.

### Steps to Reproduce

```
# python
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 18:10:19) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from conda_build.os_utils.pyldd import codefile
>>> with open('/opt/conda/conda-bld/bst_1536390062412/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold/lib/libboost_wserialization.so.1.65.0', 'rb') as f:
...   cf = codefile(f)
...   print(cf.dt_needed)
... 
['call_gmon_start', 'TOR_LIST__', '__JCR_LIST__', '', 'ors_aux', 'mpleted.6352', 'tor_idx.6354', 'me_dummy']
```

But objdump reports the correct stuff:
```
# objdump -x /opt/conda/conda-bld/bst_1536390062412/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold/lib/libboost_wserialization.so.1.65.0 | grep NEEDED
  NEEDED               libboost_serialization.so.1.65.0
  NEEDED               librt.so.1
  NEEDED               libc++.so.1
  NEEDED               libc++abi.so.1
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6
```

It seems that pyldd has seek()ed more than it should have and wandered into the `SYMBOL TABLE` instead:
```
# objdump -x /opt/conda/conda-bld/bst_1536390062412/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold/lib/libboost_wserialization.so.1.65.0 | grep -A 8 'SYMBOL TABLE'
SYMBOL TABLE:
0000000000029000 l     F .text  0000000000000000              call_gmon_start
0000000000061000 l     O .ctors 0000000000000000              __CTOR_LIST__
0000000000061040 l     O .dtors 0000000000000000              __DTOR_LIST__
0000000000061050 l     O .jcr   0000000000000000              __JCR_LIST__
0000000000029020 l     F .text  0000000000000000              __do_global_dtors_aux
0000000000063000 l     O .bss   0000000000000001              completed.6352
0000000000063008 l     O .bss   0000000000000008              dtor_idx.6354
00000000000290a0 l     F .text  0000000000000000              frame_dummy
```

Surprisingly of the many builds that I did with lld, this is the only DSO so far on which pyldd is reporting an error. DSO attached.
[libboost_wserialization.so.1.65.0.gz](https://github.com/conda/conda-build/files/2363275/libboost_wserialization.so.1.65.0.gz)




Discussion:
Also note that this happened only with the debug build of boost and that too on only one DSO. The same  DSO on the non debug build didn't face this issue.
Some weird corner case, not sure when/if I'll get round to looking at it since I'd prefer we use LIEF instead.
pyldd is loading strings from the wrong elfsection, section 35 (.strtab) rather than section 37 (.dynstr).  For some reason the .strtab section reports a very large size so the `find_section_and_offset` returns it.

Resolving patch:
diff --git a/conda_build/os_utils/pyldd.py b/conda_build/os_utils/pyldd.py
--- a/conda_build/os_utils/pyldd.py
+++ b/conda_build/os_utils/pyldd.py
@@ -897,6 +897,10 @@ def find_section_and_offset(self, addr):
         'Can be called immediately after the elfsections have been constructed'
         for es in self.elfsections:
             if addr >= es.sh_addr and addr < es.sh_addr + es.sh_size:
+                # sections which do not appear in the memory image of the
+                # process should be skipped
+                if es.sh_addr == 0:
+                    continue
                 return es, addr - es.sh_addr
         return None, None
 


Test patch: