Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-1460

Infinite loop on shiboken2 import in a PyInstaller-frozen python application located on a network-mapped drive (Windows)

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P4: Low
    • 5.15.4
    • 5.15.2, 6.0.0
    • Shiboken
    • None
    • Windows 10, python3
    • Windows
    • 86be8c1ca5936680d65bde8817c5ba09238e3700 (pyside/pyside-setup/6.0) 131a1c17eed13171bf09ba42b2205760580e4f24 (pyside/pyside-setup/dev) e034d5085d26f6703cf907caf78292d9a7861aa2 (pyside/pyside-setup/5.15)

    Description

      When a python application that uses PySide2 is frozen using PyInstaller and launched from a network-mapped drive under Windows, the import of shiboken2 causes an infinite loop.

      The import of shiboken2 calls _init_pyside_extension(), which is where the infinite loop occurs. Interrupting the program with Ctrl+C shows an error that indicates that the issue is occurring in the "part 2" of signature initialization.

      Specifically, the problem is the loop in the following block of bootstrap python code that is executed during part 2 of signature initialization:

      ...
          try:
              import shiboken2 as root
          except ImportError:
              # uninstalled case without ctest, try only this one which has __init__:
              import shibokenmodule as root
          rp = os.path.realpath(os.path.dirname(root.__file__))
          # This can be the shiboken2 directory or the binary module, so search.
          look_for = os.path.join("files.dir", "shibokensupport", "signature", "loader.py")
          while len(rp) > 3 and not os.path.exists(os.path.join(rp, look_for)):
              rp = os.path.abspath(os.path.join(rp, ".."))
      ...
      

      In a PyInstaller-frozen application, the python modules are collected in an archive that's embedded in the executable, so the module does not exist as an on-disk file.

      When run from a local drive, the loop will eventually reach the drive root, and abort due to path length not being greater than 3 (on Windows, it will be equal, e.g., c:\ ). And in subsequent code, it is determined that the loader module does not exist as a file, and sys.pyside_uses_embedding is set to True, and all is well...

      On the network-mapped drive, however, the os.path.realpath() call turns the mapped drive letter into \\host\share, which is the drive's root. And since that root's length always exceeds 3, the loop is stuck ad infinitum trying to jump one level above the root...

      A possible way to avoid this issue would be to replace the length-based check with a change-based one, or by adding an additional break-on-non-change clause into the loop itself, e.g.:

      ...
          while len(rp) > 3 and not os.path.exists(os.path.join(rp, look_for)):
              new_rp = os.path.abspath(os.path.join(rp, ".."))
              if rp == new_rp:
                  break
              rp = new_rp
      ...
      

      The issue affects both PySide2 5.15.2 (and earlier) and 6.0.

      Attachments

        For Gerrit Dashboard: PYSIDE-1460
        # Subject Branch Project Status CR V

        Activity

          People

            kleint Friedemann Kleint
            rok.mandeljc Rok Mandeljc
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes