Skip to content

Commit 0332605

Browse files
committed
Fix segfaults in _ctypes due to invalid argtypes
Signed-off-by: Nguyen Viet Dung <29406816+magnified103@users.noreply.github.com>
1 parent d3d94e0 commit 0332605

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

Lib/test/test_ctypes/test_prototypes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,23 @@ def test_paramflags(self):
7171

7272
self.assertEqual(func(None), None)
7373
self.assertEqual(func(input=None), None)
74+
75+
def test_invalid_paramflags(self):
76+
proto = CFUNCTYPE(c_int, c_char_p)
77+
with self.assertRaises(ValueError):
78+
func = proto(("myprintf", testdll), ((1, "fmt"), (1, "arg1")))
79+
80+
def test_invalid_setattr_argtypes(self):
81+
proto = CFUNCTYPE(c_int, c_char_p)
82+
func = proto(("myprintf", testdll), ((1, "fmt"),))
83+
84+
self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types",
85+
setattr, func, "argtypes", 123)
86+
self.assertEqual(func.argtypes, (c_char_p,))
87+
88+
self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes",
89+
setattr, func, "argtypes", (c_char_p, c_int))
90+
self.assertEqual(func.argtypes, (c_char_p,))
7491

7592

7693
def test_int_pointer_arg(self):

Modules/_ctypes/_ctypes.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3647,6 +3647,9 @@ atomic_xgetref(PyObject *obj, PyObject **field)
36473647
#endif
36483648
}
36493649

3650+
static int
3651+
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes);
3652+
36503653

36513654

36523655
/*[clinic input]
@@ -3762,14 +3765,27 @@ _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
37623765
{
37633766
PyObject *converters;
37643767

3768+
PyTypeObject *type = Py_TYPE(self);
3769+
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
3770+
37653771
if (value == NULL || value == Py_None) {
3772+
/* Verify paramflags again due to constraints with argtypes */
3773+
if (!_validate_paramflags(st, type, self->paramflags, value)) {
3774+
return -1;
3775+
}
3776+
37663777
atomic_xsetref(&self->argtypes, NULL);
37673778
atomic_xsetref(&self->converters, NULL);
37683779
} else {
3769-
ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
37703780
converters = converters_from_argtypes(st, value);
37713781
if (!converters)
37723782
return -1;
3783+
3784+
/* Verify paramflags again due to constraints with argtypes */
3785+
if (!_validate_paramflags(st, type, self->paramflags, value)) {
3786+
Py_DECREF(converters);
3787+
return -1;
3788+
}
37733789
atomic_xsetref(&self->converters, converters);
37743790
Py_INCREF(value);
37753791
atomic_xsetref(&self->argtypes, value);
@@ -3899,10 +3915,9 @@ _check_outarg_type(ctypes_state *st, PyObject *arg, Py_ssize_t index)
38993915

39003916
/* Returns 1 on success, 0 on error */
39013917
static int
3902-
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
3918+
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes)
39033919
{
39043920
Py_ssize_t i, len;
3905-
PyObject *argtypes;
39063921

39073922
StgInfo *info;
39083923
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
@@ -3913,9 +3928,11 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
39133928
"abstract class");
39143929
return 0;
39153930
}
3916-
argtypes = info->argtypes;
3931+
if (argtypes == NULL || argtypes == Py_None) {
3932+
argtypes = info->argtypes;
3933+
}
39173934

3918-
if (paramflags == NULL || info->argtypes == NULL)
3935+
if (paramflags == NULL || argtypes == NULL)
39193936
return 1;
39203937

39213938
if (!PyTuple_Check(paramflags)) {
@@ -3925,7 +3942,7 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
39253942
}
39263943

39273944
len = PyTuple_GET_SIZE(paramflags);
3928-
if (len != PyTuple_GET_SIZE(info->argtypes)) {
3945+
if (len != PyTuple_GET_SIZE(argtypes)) {
39293946
PyErr_SetString(PyExc_ValueError,
39303947
"paramflags must have the same length as argtypes");
39313948
return 0;
@@ -4101,7 +4118,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
41014118
#endif
41024119
#undef USE_DLERROR
41034120
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
4104-
if (!_validate_paramflags(st, type, paramflags)) {
4121+
if (!_validate_paramflags(st, type, paramflags, NULL)) {
41054122
Py_DECREF(ftuple);
41064123
return NULL;
41074124
}
@@ -4145,7 +4162,7 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
41454162
paramflags = NULL;
41464163

41474164
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
4148-
if (!_validate_paramflags(st, type, paramflags)) {
4165+
if (!_validate_paramflags(st, type, paramflags, NULL)) {
41494166
return NULL;
41504167
}
41514168
self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds);

0 commit comments

Comments
 (0)