Content-Length: 397157 | pFad | http://github.com/python/cpython/pull/136878/files

24 gh-83424: Allow empty name if handle is non-null when create ctypes.CDLL by aisk · Pull Request #136878 · python/cpython · GitHub
Skip to content

gh-83424: Allow empty name if handle is non-null when create ctypes.CDLL #136878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 45 additions & 36 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class CFunctionType(_CFuncPtr):
return CFunctionType

if _os.name == "nt":
from _ctypes import LoadLibrary as _dlopen
from _ctypes import LoadLibrary as _LoadLibrary
from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL

_win_functype_cache = {}
Expand Down Expand Up @@ -410,52 +410,61 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
use_errno=False,
use_last_error=False,
winmode=None):
class _FuncPtr(_CFuncPtr):
_flags_ = self._func_flags_
_restype_ = self._func_restype_
if use_errno:
_flags_ |= _FUNCFLAG_USE_ERRNO
if use_last_error:
_flags_ |= _FUNCFLAG_USE_LASTERROR

self._FuncPtr = _FuncPtr
if name:
name = _os.fspath(name)

self._handle = self._load_library(name, mode, handle, winmode)

if _os.name == "nt":
def _load_library(self, name, mode, handle, winmode):
if winmode is not None:
mode = winmode
else:
import nt as _nt
mode = _nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
# WINAPI LoadLibrary searches for a DLL if the given name
# is not fully qualified with an explicit drive. For POSIX
# compatibility, and because the DLL search path no longer
# contains the working directory, begin by fully resolving
# any name that contains a path separator.
if name is not None and ('/' in name or '\\' in name):
name = _nt._getfullpathname(name)
mode |= _nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
self._name = name
if handle is not None:
return handle
return _LoadLibrary(self._name, mode)

else:
def _load_library(self, name, mode, handle, winmode):
if _sys.platform.startswith("aix"):
"""When the name contains ".a(" and ends with ")",
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
archive(member) syntax for dlopen(), and the mode is adjusted.
Otherwise, name is presented to dlopen() as a file argument.
"""
if name and name.endswith(")") and ".a(" in name:
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
# If the filename that has been provided is an iOS/tvOS/watchOS
# .fwork file, dereference the location to the true origen of the
# binary.
if name.endswith(".fwork"):
if name and name.endswith(".fwork"):
with open(name) as f:
name = _os.path.join(
_os.path.dirname(_sys.executable),
f.read().strip()
)

self._name = name
flags = self._func_flags_
if use_errno:
flags |= _FUNCFLAG_USE_ERRNO
if use_last_error:
flags |= _FUNCFLAG_USE_LASTERROR
if _sys.platform.startswith("aix"):
"""When the name contains ".a(" and ends with ")",
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
archive(member) syntax for dlopen(), and the mode is adjusted.
Otherwise, name is presented to dlopen() as a file argument.
"""
if name and name.endswith(")") and ".a(" in name:
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
if _os.name == "nt":
if winmode is not None:
mode = winmode
else:
import nt
mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
if '/' in name or '\\' in name:
self._name = nt._getfullpathname(self._name)
mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR

class _FuncPtr(_CFuncPtr):
_flags_ = flags
_restype_ = self._func_restype_
self._FuncPtr = _FuncPtr

if handle is None:
self._handle = _dlopen(self._name, mode)
else:
self._handle = handle
self._name = name
return _dlopen(name, mode)

def __repr__(self):
return "<%s '%s', handle %x at %#x>" % \
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_ctypes/test_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ def test_load_ordinal_functions(self):

self.assertRaises(AttributeError, dll.__getitem__, 1234)

@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
def test_load_without_name_and_with_handle(self):
handle = ctypes.windll.kernel32._handle
lib = ctypes.WinDLL(name=None, handle=handle)
self.assertIs(handle, lib._handle)

@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
def test_1703286_A(self):
# On winXP 64-bit, advapi32 loads at an address that does
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allows creating a :class:`ctypes.CDLL` without name when passing a handle as
an argument.
Loading








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/136878/files

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy