You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
cdll.LoadLibrary allows None as an argument #78773
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2018-09-05.21:35:41.405>labels= ['3.11', 'invalid', 'docs']
title='cdll.LoadLibrary allows None as an argument'updated_at=<Date2021-11-19.04:06:58.621>user='https://github.com/superbobry'
LoadLibrary in Python 2.7 through 3.7 accepts None as an argument. I wonder if this has been allowed for a reason? If not, it should probably be changed to raise a TypeError instead.
>>> ctypes.cdll.LoadLibrary(None)
<CDLL 'None', handle fffffffffffffffe at 10eedbe90>
Interestingly, on Python 2.7 LoadLibrary explicitly mentions None as allowed in the error message:
>>> ctypes.cdll.LoadLibrary(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "[...]/ctypes/__init__.py", line 444, in LoadLibrary
return self._dlltype(name)
File "[...]/ctypes/__init__.py", line 366, in __init__
self._handle = _dlopen(self._name, mode)
TypeError: dlopen() argument 1 must be string or None, not int
A side-effect of None being allowed is that chaining find_library and LoadLibrary is error-prone:
>>> ctypes.cdll.LoadLibrary(find_library("foobar"))
<CDLL 'None', handle fffffffffffffffe at 10ef35fd0>
This isn't documented, but CDLL(None) is translated to dlopen(NULL), which "causes a search for a symbol in the main program, followed by all shared libraries loaded at program startup, and then all shared libraries loaded by dlopen() with the flag RTLD_GLOBAL" (https://linux.die.net/man/3/dlopen).
This is sometimes useful because it lets you look up a symbol in an already-loaded library without needing to give the library's name. For example:
>>> import ctypes
>>> dll = ctypes.CDLL(None)
>>> dll.printf
<_FuncPtr object at 0x7f3427d547c0>
>>> dll.PyObject_Str
<_FuncPtr object at 0x7f3427d54880>
We do need to document this in ctypes.rst. Quite a bit of code depends on ctypes.CDLL(None) and similar to get at symbols linked into the interpreter or already dlopened into the process these days. It works on Linux; I'm assuming it likely does on everything POSIXy.
If file is a null pointer, dlopen() shall return a global symbol table handle for the currently running process image. This symbol table handle shall provide access to the symbols from an ordered set of executable object files consisting of the original program image file, any executable object files loaded at program start-up as specified by that process file (for example, shared libraries), and the set of executable object files loaded using dlopen() operations with the RTLD_GLOBAL flag. As the latter set of executable object files can change during execution, the set of symbols made available by this symbol table handle can also change dynamically.
Activity
superbobry commentedon Sep 5, 2018
LoadLibrary in Python 2.7 through 3.7 accepts None as an argument. I wonder if this has been allowed for a reason? If not, it should probably be changed to raise a TypeError instead.
>>> ctypes.cdll.LoadLibrary(None) <CDLL 'None', handle fffffffffffffffe at 10eedbe90>Interestingly, on Python 2.7 LoadLibrary explicitly mentions None as allowed in the error message:
>>> ctypes.cdll.LoadLibrary(42) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "[...]/ctypes/__init__.py", line 444, in LoadLibrary return self._dlltype(name) File "[...]/ctypes/__init__.py", line 366, in __init__ self._handle = _dlopen(self._name, mode) TypeError: dlopen() argument 1 must be string or None, not intA side-effect of None being allowed is that chaining find_library and LoadLibrary is error-prone:
>>> ctypes.cdll.LoadLibrary(find_library("foobar")) <CDLL 'None', handle fffffffffffffffe at 10ef35fd0>mhsmith commentedon Feb 10, 2020
This isn't documented, but CDLL(None) is translated to dlopen(NULL), which "causes a search for a symbol in the main program, followed by all shared libraries loaded at program startup, and then all shared libraries loaded by dlopen() with the flag RTLD_GLOBAL" (https://linux.die.net/man/3/dlopen).
This is sometimes useful because it lets you look up a symbol in an already-loaded library without needing to give the library's name. For example:
vstinner commentedon Feb 10, 2020
I'm using LoadLibrary(None) commonly to load symbols in Python itself ;-)
vstinner commentedon Feb 11, 2020
In clear, it's a feature, not a bug.
gpshead commentedon Nov 19, 2021
We do need to document this in ctypes.rst. Quite a bit of code depends on ctypes.CDLL(None) and similar to get at symbols linked into the interpreter or already dlopened into the process these days. It works on Linux; I'm assuming it likely does on everything POSIXy.
encukou commentedon Feb 4, 2025
Indeed. POSIX says:
pythongh-78773: Document CDLL(None)
pythongh-78773: Reorganize dynamic library loading docs
gh-78773: Improve ctypes dynamic library loading docs (GH-145313)
pythongh-78773: Improve ctypes dynamic library loading docs (pythonGH…
[3.14] gh-78773: Improve ctypes dynamic library loading docs (GH-145313…
encukou commentedon Mar 9, 2026
Docs are now in.
pythongh-78773: Improve ctypes dynamic library loading docs (pythonGH…