lief-project / LIEF

LIEF - Library to Instrument Executable Formats
https://lief-project.github.io/
Apache License 2.0
4.29k stars 602 forks source link

"import lief" not work on 0.13.0 #901

Closed DiamondHunters closed 1 year ago

DiamondHunters commented 1 year ago

Describe the bug

>>> import lief
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/lief/__init__.py", line 2, in <module>
    from . import _lief
ImportError: cannot import name '_lief' from partially initialized module 'lief' (most likely due to a circular import) (/usr/local/lib/python3.8/dist-packages/lief/__init__.py)
>>>

To Reproduce Steps to reproduce the behavior: pip3 install lief==0.13.0 python3 -c "import lief"

Expected behavior like lief 0.12.3 works:

rock@rock-5b:~$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lief
>>> lief
<module 'lief' from '/usr/local/lib/python3.8/dist-packages/lief.cpython-38-aarch64-linux-gnu.so'>

Environment (please complete the following information):

 rock@rock-5b:~$ sudo pip3 uninstall lief
Found existing installation: lief 0.13.0
Uninstalling lief-0.13.0:
  Would remove:
    /usr/local/bin/elf_reader.py
    /usr/local/bin/macho_reader.py
    /usr/local/bin/pe_reader.py
    /usr/local/lib/python3.8/dist-packages/lief-0.13.0.dist-info/*
    /usr/local/lib/python3.8/dist-packages/lief/*
Proceed (y/n)? y
  Successfully uninstalled lief-0.13.0
rock@rock-5b:~$ sudo pip3 install lief
Collecting lief
  Using cached lief-0.13.0-cp38-cp38-manylinux2014_aarch64.whl (4.2 MB)
Installing collected packages: lief
Successfully installed lief-0.13.0
rock@rock-5b:~$ neofetch
            .-/+oossssoo+/-.               rock@rock-5b
        `:+ssssssssssssssssss+:`           ------------
      -+ssssssssssssssssssyyssss+-         OS: Ubuntu 20.04 LTS aarch64
    .ossssssssssssssssssdMMMNysssso.       Host: Radxa ROCK 5B
   /ssssssssssshdmmNNmmyNMMMMhssssss/      Kernel: 5.10.110-99-rockchip-gf1011079b3c0
  +ssssssssshmydMMMMMMMNddddyssssssss+     Uptime: 8 hours, 34 mins
 /sssssssshNMMMyhhyyyyhmNMMMNhssssssss/    Packages: 1139 (dpkg)
.ssssssssdMMMNhsssssssssshNMMMdssssssss.   Shell: bash 5.0.16
+sssshhhyNMMNyssssssssssssyNMMMysssssss+   Terminal: /dev/pts/40
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   CPU: (8) @ 1.800GHz
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   Memory: 1426MiB / 15721MiB
+sssshhhyNMMNyssssssssssssyNMMMysssssss+
.ssssssssdMMMNhsssssssssshNMMMdssssssss.
 /sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
  +sssssssssdmydMMMMMMMMddddyssssssss+
   /ssssssssssshdmNNNNmyNMMMMhssssss/
    .ossssssssssssssssssdMMMNysssso.
      -+sssssssssssssssssyyyssss+-
        `:+ssssssssssssssssss+:`
            .-/+oossssoo+/-.

Additional context

rock@rock-5b:~$ pip3 list |grep lief
lief                0.13.0
DiamondHunters commented 1 year ago

I found binary files with incorrect architecture name in the .whl package

rock@rock-5b:~$ tree /usr/local/lib/python3.8/dist-packages/lief
/usr/local/lib/python3.8/dist-packages/lief
├── Android.pyi
├── ART.pyi
├── DEX.pyi
├── ELF.pyi
├── __init__.py
├── __init__.pyi
├── **_lief.cpython-38-x86_64-linux-gnu.so**
├── logging.pyi
├── MachO.pyi
├── OAT.pyi
├── PE.pyi
├── __pycache__
│   └── __init__.cpython-38.pyc
├── py.typed
└── VDEX.pyi

1 directory, 14 files

I unzipped the whl package and confirmed the issue lief-0.13.0-cp310-cp310-manylinux2014_aarch64.whl

rename _lief.cpython-38-x86_64-linux-gnu.so to _lief.cpython-38-aarch64-linux-gnu.so then python load this lib

DiamondHunters commented 1 year ago

At there: https://github.com/lief-project/LIEF/blob/f796720f633415d7f2051e082a47e1789e1fce9c/api/python/setup.py#L324 Used 'get_ext_filename' to obtain the compilation suffix name.

 def get_ext_filename(self, fullname):
        so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX')
        if so_ext:
            filename = os.path.join(*fullname.split('.')) + so_ext
        else:
            filename = _build_ext.get_ext_filename(self, fullname)
            so_ext = get_config_var('EXT_SUFFIX')

        if fullname in self.ext_map:
            ext = self.ext_map[fullname]
            use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix()
            if use_abi3:
                filename = filename[:-len(so_ext)]
                so_ext = get_abi3_suffix()
                filename = filename + so_ext
            if isinstance(ext, Library):
                fn, ext = os.path.splitext(filename)
                return self.shlib_compiler.library_filename(fn, libtype)
            elif use_stubs and ext._links_to_dynamic:
                d, fn = os.path.split(filename)
                return os.path.join(d, 'dl-' + fn)
        return filename 

It's only related to building machines. And for the correct suffix name, it can be configured using the 'SETUPTOOLS_EXT_SUFFIX' environment variable But we need to specify the py version, so I am looking for an elegant solution.

DiamondHunters commented 1 year ago

The root cause is _PYTHON_HOST_PLATFORM in sh file not effective

DiamondHunters commented 1 year ago

Actually,after I read the source code of distutils,I found that the results of get_ext_filename are only related to EXT_SUFFIX. _PYTHON_HOST_PLATFORM only affects APIs such as get_host_platform ,get_platform refer to https://github.com/pypa/setuptools/issues/2722 The solution is to set SETUPTOOLS_EXT_SUFFIX environment variable

romainthomas commented 1 year ago

Thank you @DiamondHunters for your investigation and your PR. I'll do the review in the next couple of days

DiamondHunters commented 1 year ago

https://github.com/lief-project/LIEF/commit/0714d2e7832cb7d28e5cc91b997094f97188a33b

ostefano commented 1 year ago

@romainthomas is a new release needed to 'distribute' the fix?

romainthomas commented 1 year ago

Yes I'll create a patch release in the next couple of weeks