Skip to content

Commit 135198d

Browse files
encukoumagnified103blurb-it[bot]Yzi-Li
authored
[3.13] gh-138008: Fix segfaults in _ctypes due to invalid argtypes (GH-138285) (#138746)
(cherry picked from commit 1ce0553) Signed-off-by: Nguyen Viet Dung <[email protected]> Signed-off-by: Nguyen Viet Dung <[email protected]> Co-authored-by: Dung Nguyen <[email protected]> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Yongzi Li <[email protected]>
1 parent 5e59aef commit 135198d

File tree

3 files changed

+52
-15
lines changed

3 files changed

+52
-15
lines changed

Lib/test/test_ctypes/test_prototypes.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,32 @@ def test_paramflags(self):
7272
self.assertEqual(func(None), None)
7373
self.assertEqual(func(input=None), None)
7474

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+
with self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types"):
85+
func.argtypes = 123
86+
self.assertEqual(func.argtypes, (c_char_p,))
87+
88+
with self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes"):
89+
func.argtypes = (c_char_p, c_int)
90+
self.assertEqual(func.argtypes, (c_char_p,))
91+
92+
def test_paramflags_outarg(self):
93+
proto = CFUNCTYPE(c_int, c_char_p, c_int)
94+
with self.assertRaisesRegex(TypeError, "must be a pointer type"):
95+
func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
96+
97+
proto = CFUNCTYPE(c_int, c_char_p, c_void_p)
98+
func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
99+
with self.assertRaisesRegex(TypeError, "must be a pointer type"):
100+
func.argtypes = (c_char_p, c_int)
75101

76102
def test_int_pointer_arg(self):
77103
func = testdll._testfunc_p_p
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix segmentation faults in the :mod:`ctypes` module due to invalid :attr:`~ctypes._CFuncPtr.argtypes`. Patch by Dung Nguyen.

Modules/_ctypes/_ctypes.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3396,6 +3396,9 @@ generic_pycdata_new(ctypes_state *st,
33963396
PyCFuncPtr_Type
33973397
*/
33983398

3399+
static int
3400+
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes);
3401+
33993402
static int
34003403
PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
34013404
{
@@ -3470,21 +3473,26 @@ PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
34703473
}
34713474

34723475
static int
3473-
PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
3476+
PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *value, void *Py_UNUSED(ignored))
34743477
{
3475-
PyObject *converters;
3476-
3477-
if (ob == NULL || ob == Py_None) {
3478+
if (value == NULL || value == Py_None) {
34783479
Py_CLEAR(self->converters);
34793480
Py_CLEAR(self->argtypes);
34803481
} else {
3481-
ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
3482-
converters = converters_from_argtypes(st, ob);
3482+
PyTypeObject *type = Py_TYPE(self);
3483+
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
3484+
PyObject *converters = converters_from_argtypes(st, value);
34833485
if (!converters)
34843486
return -1;
3487+
3488+
/* Verify paramflags again due to constraints with argtypes */
3489+
if (!_validate_paramflags(st, type, self->paramflags, value)) {
3490+
Py_DECREF(converters);
3491+
return -1;
3492+
}
34853493
Py_XSETREF(self->converters, converters);
3486-
Py_INCREF(ob);
3487-
Py_XSETREF(self->argtypes, ob);
3494+
Py_INCREF(value);
3495+
Py_XSETREF(self->argtypes, value);
34883496
}
34893497
return 0;
34903498
}
@@ -3606,10 +3614,9 @@ _check_outarg_type(ctypes_state *st, PyObject *arg, Py_ssize_t index)
36063614

36073615
/* Returns 1 on success, 0 on error */
36083616
static int
3609-
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
3617+
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes)
36103618
{
36113619
Py_ssize_t i, len;
3612-
PyObject *argtypes;
36133620

36143621
StgInfo *info;
36153622
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
@@ -3620,10 +3627,13 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
36203627
"abstract class");
36213628
return 0;
36223629
}
3623-
argtypes = info->argtypes;
3630+
if (argtypes == NULL) {
3631+
argtypes = info->argtypes;
3632+
}
36243633

3625-
if (paramflags == NULL || info->argtypes == NULL)
3634+
if (paramflags == NULL || argtypes == NULL) {
36263635
return 1;
3636+
}
36273637

36283638
if (!PyTuple_Check(paramflags)) {
36293639
PyErr_SetString(PyExc_TypeError,
@@ -3632,7 +3642,7 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
36323642
}
36333643

36343644
len = PyTuple_GET_SIZE(paramflags);
3635-
if (len != PyTuple_GET_SIZE(info->argtypes)) {
3645+
if (len != PyTuple_GET_SIZE(argtypes)) {
36363646
PyErr_SetString(PyExc_ValueError,
36373647
"paramflags must have the same length as argtypes");
36383648
return 0;
@@ -3807,7 +3817,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
38073817
#endif
38083818
#undef USE_DLERROR
38093819
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
3810-
if (!_validate_paramflags(st, type, paramflags)) {
3820+
if (!_validate_paramflags(st, type, paramflags, NULL)) {
38113821
Py_DECREF(ftuple);
38123822
return NULL;
38133823
}
@@ -3849,7 +3859,7 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
38493859
paramflags = NULL;
38503860

38513861
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
3852-
if (!_validate_paramflags(st, type, paramflags)) {
3862+
if (!_validate_paramflags(st, type, paramflags, NULL)) {
38533863
return NULL;
38543864
}
38553865
self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds);

0 commit comments

Comments
 (0)