Skip to content

Commit

Permalink
building: retry mechanism: enable retry on winerror 110
Browse files Browse the repository at this point in the history
Add winerror 110 (`ERROR_OPEN_FAILED`) to the list of permissible
error codes for the retry mechanism that attempts to mitigate
build failures due to anti-virus program interference.

At the same time, reorganize the exception-checking code by
merging all Windows specific code into a single branch. This allows
us to re-use `_ALLOWED_WINERROR` with both `pywintypes.error` and
`OSError`. With the latter, we now compare the `winerror` attribute
as a fall back after `errno` comparison.
  • Loading branch information
rokm committed Dec 2, 2023
1 parent dac472b commit ac7f683
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 11 deletions.
30 changes: 19 additions & 11 deletions PyInstaller/building/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,28 +965,36 @@ def _is_allowed_exception(e):
"""
Helper to determine whether the given exception is eligible for retry or not.
"""
if is_win:
from PyInstaller.compat import pywintypes

if isinstance(e, PermissionError):
# Always retry on all instances of PermissionError
return True
elif is_win and isinstance(e, OSError):
# For other types of OSError, validate errno (the values below are specific to Windows)
elif is_win:
from PyInstaller.compat import pywintypes

# Windows-specific errno and winerror codes.
# https://learn.microsoft.com/en-us/cpp/c-runtime-library/errno-constants
_ALLOWED_ERRNO = {
13, # EACCES (would typically be a PermissionError instead)
22, # EINVAL (reported to be caused by Crowdstrike; see #7840)
}
if e.errno in _ALLOWED_ERRNO:
return True
elif is_win and isinstance(e, pywintypes.error):
# pywintypes.error is raised by helper functions that use win32 C API bound via pywin32-ctypes.
# https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
_ALLOWED_WINERROR = {
5, # ERROR_ACCESS_DENIED (reported in #7825)
32, # ERROR_SHARING_VIOLATION (exclusive lock via `CreateFileW` flags, or via `_locked`).
110, # ERROR_OPEN_FAILED (reported in #8138)
}
if e.winerror in _ALLOWED_WINERROR:
return True
if isinstance(e, OSError):
# For OSError exceptions other than PermissionError, validate errno.
if e.errno in _ALLOWED_ERRNO:
return True
# OSError typically translates `winerror` into `errno` equivalent; but try to match the original
# values as a fall back, just in case. `OSError.winerror` attribute exists only on Windows.
if e.winerror in _ALLOWED_WINERROR:
return True
elif isinstance(e, pywintypes.error):
# pywintypes.error is raised by helper functions that use win32 C API bound via pywin32-ctypes.
if e.winerror in _ALLOWED_WINERROR:
return True
return False

func_name = func.__name__
Expand Down
3 changes: 3 additions & 0 deletions news/8138.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(Windows) Add Windows error code 110 (``ERROR_OPEN_FAILED``) to the
list of error codes eligible for the retry mechanism that attempts to
mitigate build failures due to anti-virus program interference.

0 comments on commit ac7f683

Please sign in to comment.