Skip to content

Commit 6dddf0b

Browse files
[3.15] gh-159739: Detect recursive untyped ctypes arguments (GH-160194) (#160350)
_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. (cherry picked from commit 3e19e04) Co-authored-by: Jelle Zijlstra <jelle@openai.com>
1 parent 5c50b6a commit 6dddf0b

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
@@ -213,6 +213,10 @@ class A:
213213
with self.assertRaises(RecursionError):
214214
c_type.from_param(a)
215215

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

217221
class AsParamWrapper:
218222
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()
@@ -744,8 +745,12 @@ static int ConvParam(ctypes_state *st,
744745
attribute)
745746
*/
746747
if (arg) {
747-
int result;
748-
result = ConvParam(st, arg, index, pa);
748+
if (_Py_EnterRecursiveCall(" while processing _as_parameter_")) {
749+
Py_DECREF(arg);
750+
return -1;
751+
}
752+
int result = ConvParam(st, arg, index, pa);
753+
_Py_LeaveRecursiveCall();
749754
Py_DECREF(arg);
750755
return result;
751756
}

0 commit comments

Comments
 (0)