self.assertEqual(func(None), None)
self.assertEqual(func(input=None), None)
+ def test_invalid_paramflags(self):
+ proto = CFUNCTYPE(c_int, c_char_p)
+ with self.assertRaises(ValueError):
+ func = proto(("myprintf", testdll), ((1, "fmt"), (1, "arg1")))
+
+ def test_invalid_setattr_argtypes(self):
+ proto = CFUNCTYPE(c_int, c_char_p)
+ func = proto(("myprintf", testdll), ((1, "fmt"),))
+
+ with self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types"):
+ func.argtypes = 123
+ self.assertEqual(func.argtypes, (c_char_p,))
+
+ with self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes"):
+ func.argtypes = (c_char_p, c_int)
+ self.assertEqual(func.argtypes, (c_char_p,))
+
+ def test_paramflags_outarg(self):
+ proto = CFUNCTYPE(c_int, c_char_p, c_int)
+ with self.assertRaisesRegex(TypeError, "must be a pointer type"):
+ func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
+
+ proto = CFUNCTYPE(c_int, c_char_p, c_void_p)
+ func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
+ with self.assertRaisesRegex(TypeError, "must be a pointer type"):
+ func.argtypes = (c_char_p, c_int)
def test_int_pointer_arg(self):
func = testdll._testfunc_p_p
#endif
}
+static int
+_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes);
+
/*[clinic input]
_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
/*[clinic end generated code: output=596a36e2ae89d7d1 input=c4627573e980aa8b]*/
{
- PyObject *converters;
-
if (value == NULL || value == Py_None) {
atomic_xsetref(&self->argtypes, NULL);
atomic_xsetref(&self->converters, NULL);
} else {
- ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
- converters = converters_from_argtypes(st, value);
+ PyTypeObject *type = Py_TYPE(self);
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
+
+ PyObject *converters = converters_from_argtypes(st, value);
if (!converters)
return -1;
+
+ /* Verify paramflags again due to constraints with argtypes */
+ if (!_validate_paramflags(st, type, self->paramflags, value)) {
+ Py_DECREF(converters);
+ return -1;
+ }
atomic_xsetref(&self->converters, converters);
Py_INCREF(value);
atomic_xsetref(&self->argtypes, value);
/* Returns 1 on success, 0 on error */
static int
-_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
+_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes)
{
Py_ssize_t i, len;
- PyObject *argtypes;
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
"abstract class");
return 0;
}
- argtypes = info->argtypes;
+ if (argtypes == NULL) {
+ argtypes = info->argtypes;
+ }
- if (paramflags == NULL || info->argtypes == NULL)
+ if (paramflags == NULL || argtypes == NULL) {
return 1;
+ }
if (!PyTuple_Check(paramflags)) {
PyErr_SetString(PyExc_TypeError,
}
len = PyTuple_GET_SIZE(paramflags);
- if (len != PyTuple_GET_SIZE(info->argtypes)) {
+ if (len != PyTuple_GET_SIZE(argtypes)) {
PyErr_SetString(PyExc_ValueError,
"paramflags must have the same length as argtypes");
return 0;
#endif
#undef USE_DLERROR
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
- if (!_validate_paramflags(st, type, paramflags)) {
+ if (!_validate_paramflags(st, type, paramflags, NULL)) {
Py_DECREF(ftuple);
return NULL;
}
paramflags = NULL;
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
- if (!_validate_paramflags(st, type, paramflags)) {
+ if (!_validate_paramflags(st, type, paramflags, NULL)) {
return NULL;
}
self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds);