Skip to content

Commit

Permalink
tests: add test for ctypes.CDLL incorrectly picking up builtin extens…
Browse files Browse the repository at this point in the history
…ion libraries

On linux and macOS, some of the built-ins are provided as extensions
(e.g., _sha1.cpython-39-x86_64-linux-gnu.so) that originally reside
in python3.X/lib-dynload directory. This directory is not in the
ctypes' library search path, therefore running
ctypes.CDLL('_sha1.cpython-39-x86_64-linux-gnu.so')
in python interpreter will come up empty.

In a frozen application, however, these extensions end up collected
directly in the _MEIPASS, which is searched by ctypes (because search
behavior is explicitly overriden by the hook). Therefore, trying to
load the extension's library file via ctypes.CDLL() will succeed,
resulting in inconsistent behavior between unfrozen and frozen
program.

On macOS, this causes issues with `pycryptodomex` (pyinstaller#5583), which,
due to its library search implementation, ends up with handle of
`_sha1` extension module instead of its private extension/library
 with the same name prefix.
  • Loading branch information
rokm committed Apr 13, 2021
1 parent 5898725 commit d762f1d
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions tests/functional/test_import.py
Expand Up @@ -11,6 +11,7 @@
#-----------------------------------------------------------------------------

import os
import sys
import glob
import ctypes
import ctypes.util
Expand Down Expand Up @@ -371,6 +372,31 @@ def g():
pyi_builder.test_source(source % locals(), test_id=test_id)


def test_ctypes_cdll_builtin_extension(pyi_builder):
# Take a built-in that is provided as an extension
builtin_ext = '_sha256'
if builtin_ext in sys.builtin_module_names:
# On Windows, built-ins do not seem to be extensions
pytest.skip(f"{builtin_ext} is a built-in module without extension.")

pyi_builder.test_source(
"""
import ctypes
import importlib.machinery
# Try to load CDLL with all possible extension suffices; this
# should fail in all cases, as built-in extensions should not
# be in the ctypes' search path.
builtin_ext = '{0}'
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
try:
lib = ctypes.CDLL(builtin_ext + suffix)
except OSError:
lib = None
assert lib is None, "Built-in extension picked up by ctypes.CDLL!"
""".format(builtin_ext))


# TODO: Add test-cases for the prefabricated library loaders supporting
# attribute accesses on windows. Example::
#
Expand Down

0 comments on commit d762f1d

Please sign in to comment.