Skip to content

Commit 3e19e04

Browse files
authored
gh-159739: Detect recursive untyped ctypes arguments (#160194)
_as_parameter_ chains were recursion-checked for typed arguments but not for foreign calls without argtypes. A cyclic chain could exhaust the C stack and crash before the function was called. Apply the same recursion guard to untyped conversion. Backport to 3.15 and 3.14.
1 parent 6d803ac commit 3e19e04

3 files changed

Lines changed: 12 additions & 2 deletions

File tree

‎Lib/test/test_ctypes/test_as_parameter.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ class A:
214214
with self.assertRaises(RecursionError):
215215
c_type.from_param(a)
216216

217+
function = CDLL(_ctypes_test.__file__)._testfunc_p_p
218+
with self.assertRaisesRegex(ArgumentError, 'RecursionError'):
219+
function(a)
220+
217221

218222
class AsParamWrapper:
219223
def __init__(self, param):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Detect recursive ``_as_parameter_`` chains for :mod:`ctypes` calls without argument types.

‎Modules/_ctypes/callproc.c‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ module _ctypes
9191
#define DONT_USE_SEH
9292
#endif
9393

94+
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
9495
#include "pycore_runtime.h" // _PyRuntime
9596
#include "pycore_global_objects.h"// _Py_ID()
9697
#include "pycore_traceback.h" // _PyTraceback_Add()
@@ -795,8 +796,12 @@ static int ConvParam(ctypes_state *st,
795796
attribute)
796797
*/
797798
if (arg) {
798-
int result;
799-
result = ConvParam(st, arg, index, pa);
799+
if (_Py_EnterRecursiveCall(" while processing _as_parameter_")) {
800+
Py_DECREF(arg);
801+
return -1;
802+
}
803+
int result = ConvParam(st, arg, index, pa);
804+
_Py_LeaveRecursiveCall();
800805
Py_DECREF(arg);
801806
return result;
802807
}

0 commit comments

Comments
 (0)