Skip to content

Commit

Permalink
bpo-13097: ctypes: limit callback to 1024 arguments (GH-19914)
Browse files Browse the repository at this point in the history
ctypes now raises an ArgumentError when a callback
is invoked with more than 1024 arguments.

The ctypes module allocates arguments on the stack in
ctypes_callproc() using alloca(), which is problematic
when large numbers of arguments are passed. Instead
of a stack overflow, this commit raises an ArgumentError
if more than 1024 parameters are passed.
(cherry picked from commit 29a1384)

Co-authored-by: Sean Gillespie <sean@swgillespie.me>
  • Loading branch information
miss-islington and swgillespie committed May 27, 2020
1 parent a93bf82 commit 1c4dcaf
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Lib/ctypes/test/test_callbacks.py
Expand Up @@ -287,6 +287,21 @@ def callback(check, s):
self.assertEqual(s.second, check.second)
self.assertEqual(s.third, check.third)

def test_callback_too_many_args(self):
def func(*args):
return len(args)

CTYPES_MAX_ARGCOUNT = 1024
proto = CFUNCTYPE(c_int, *(c_int,) * CTYPES_MAX_ARGCOUNT)
cb = proto(func)
args1 = (1,) * CTYPES_MAX_ARGCOUNT
self.assertEqual(cb(*args1), CTYPES_MAX_ARGCOUNT)

args2 = (1,) * (CTYPES_MAX_ARGCOUNT + 1)
with self.assertRaises(ArgumentError):
cb(*args2)


################################################################

if __name__ == '__main__':
Expand Down
@@ -0,0 +1 @@
``ctypes`` now raises an ``ArgumentError`` when a callback is invoked with more than 1024 arguments.
15 changes: 15 additions & 0 deletions Modules/_ctypes/callproc.c
Expand Up @@ -1060,6 +1060,14 @@ GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk)
#define IS_PASS_BY_REF(x) (x > 8 || !POW2(x))
#endif

/*
* bpo-13097: Max number of arguments _ctypes_callproc will accept.
*
* This limit is enforced for the `alloca()` call in `_ctypes_callproc`,
* to avoid allocating a massive buffer on the stack.
*/
#define CTYPES_MAX_ARGCOUNT 1024

/*
* Requirements, must be ensured by the caller:
* - argtuple is tuple of arguments
Expand Down Expand Up @@ -1095,6 +1103,13 @@ PyObject *_ctypes_callproc(PPROC pProc,
++argcount;
#endif

if (argcount > CTYPES_MAX_ARGCOUNT)
{
PyErr_Format(PyExc_ArgError, "too many arguments (%zi), maximum is %i",
argcount, CTYPES_MAX_ARGCOUNT);
return NULL;
}

args = (struct argument *)alloca(sizeof(struct argument) * argcount);
if (!args) {
PyErr_NoMemory();
Expand Down

0 comments on commit 1c4dcaf

Please sign in to comment.