Skip to content

Commit 874736e

Browse files
gh-82439: Clarify the behavior of argtypes under different calling conventions (GH-160065)
1 parent 01ff2e2 commit 874736e

1 file changed

Lines changed: 26 additions & 21 deletions

File tree

‎Doc/library/ctypes.rst‎

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -178,23 +178,13 @@ handle (passing ``None`` as single argument to call it with a ``NULL`` pointer):
178178
0x1d000000
179179
>>>
180180

181-
:exc:`ValueError` is raised when you call an ``stdcall`` function with the
182-
``cdecl`` calling convention, or vice versa::
183-
184-
>>> cdll.kernel32.GetModuleHandleA(None) # doctest: +WINDOWS
185-
Traceback (most recent call last):
186-
File "<stdin>", line 1, in <module>
187-
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
188-
>>>
189-
190-
>>> windll.msvcrt.printf(b"spam") # doctest: +WINDOWS
191-
Traceback (most recent call last):
192-
File "<stdin>", line 1, in <module>
193-
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
194-
>>>
195-
196-
To find out the correct calling convention you have to look into the C header
197-
file or the documentation for the function you want to call.
181+
:mod:`!ctypes` cannot determine a function's calling convention or signature.
182+
Consult the function's C header file or documentation to choose the correct calling
183+
convention and set the :attr:`~_CFuncPtr.argtypes` attribute, as described in
184+
:ref:`ctypes-specifying-required-argument-types`. Without
185+
:attr:`~_CFuncPtr.argtypes`, the number of arguments is not checked. Calling a
186+
function with an incorrect calling convention or with incorrect arguments can
187+
corrupt memory or crash Python.
198188

199189
On Windows, :mod:`!ctypes` uses win32 structured exception handling to prevent
200190
crashes from general protection faults when functions are called with invalid
@@ -586,6 +576,20 @@ prototype for a C function), and tries to convert the arguments to valid types::
586576
13
587577
>>>
588578

579+
Setting :attr:`~_CFuncPtr.argtypes` also causes :mod:`!ctypes` to raise
580+
:exc:`TypeError` if too few arguments are passed::
581+
582+
>>> printf(b"%s %d %f\n", b"X", 2)
583+
Traceback (most recent call last):
584+
File "<stdin>", line 1, in <module>
585+
TypeError: this function takes at least 4 arguments (3 given)
586+
587+
Functions using the ``stdcall`` calling convention require exactly as many
588+
arguments as there are items in :attr:`~_CFuncPtr.argtypes`. Functions using
589+
the ``cdecl`` calling convention accept additional arguments, to support
590+
variadic functions. The declaration must match the function's actual signature;
591+
ctypes cannot verify this.
592+
589593
If you have defined your own classes which you pass to function calls, you have
590594
to implement a :meth:`~_CData.from_param` class method for them to be able to use them
591595
in the :attr:`~_CFuncPtr.argtypes` sequence. The :meth:`~_CData.from_param` class method receives
@@ -1970,10 +1974,11 @@ in :mod:`!ctypes`) which inherits from the private :class:`_CFuncPtr` class:
19701974
.. attribute:: argtypes
19711975

19721976
Assign a tuple of ctypes types to specify the argument types that the
1973-
function accepts. Functions using the ``stdcall`` calling convention can
1974-
only be called with the same number of arguments as the length of this
1975-
tuple; functions using the C calling convention accept additional,
1976-
unspecified arguments as well.
1977+
function accepts. :exc:`TypeError` is raised if the function is called
1978+
with fewer arguments than the length of this tuple. Functions using the
1979+
``stdcall`` calling convention also raise :exc:`TypeError` if called with
1980+
more arguments; functions using the ``cdecl`` calling convention accept
1981+
additional, unspecified arguments as well.
19771982

19781983
When a foreign function is called, each actual argument is passed to the
19791984
:meth:`~_CData.from_param` class method of the items in the :attr:`argtypes`

0 commit comments

Comments
 (0)