Skip to content

Commit 5002aa6

Browse files
[3.15] gh-82439: Clarify the behavior of argtypes under different calling conventions (GH-160065) (GH-160072)
(cherry picked from commit 874736e) Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
1 parent a2ab4ad commit 5002aa6

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
@@ -1913,10 +1917,11 @@ in :mod:`!ctypes`) which inherits from the private :class:`_CFuncPtr` class:
19131917
.. attribute:: argtypes
19141918

19151919
Assign a tuple of ctypes types to specify the argument types that the
1916-
function accepts. Functions using the ``stdcall`` calling convention can
1917-
only be called with the same number of arguments as the length of this
1918-
tuple; functions using the C calling convention accept additional,
1919-
unspecified arguments as well.
1920+
function accepts. :exc:`TypeError` is raised if the function is called
1921+
with fewer arguments than the length of this tuple. Functions using the
1922+
``stdcall`` calling convention also raise :exc:`TypeError` if called with
1923+
more arguments; functions using the ``cdecl`` calling convention accept
1924+
additional, unspecified arguments as well.
19201925

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

0 commit comments

Comments
 (0)