Skip to content

Commit 0b373d5

Browse files
Add some extra checks and tests
1 parent eacc724 commit 0b373d5

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

Lib/ctypes/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,9 @@ def POINTER(cls):
276276
except AttributeError:
277277
pass
278278
if isinstance(cls, str):
279-
return type(f'LP_{cls}', (_Pointer,), {}) # deprecated
279+
return type(f'LP_{cls}', (_Pointer,), {})
280280
return type(f'LP_{cls.__name__}', (_Pointer,), {'_type_': cls})
281+
281282
def pointer(arg):
282283
typ = POINTER(type(arg))
283284
return typ(arg)

Lib/test/test_ctypes/test_pointers.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,31 @@ def test_pointer_type_str_name(self):
216216
def test_abstract(self):
217217
self.assertRaises(TypeError, _Pointer.set_type, 42)
218218

219+
def test_pointer_types_equal(self):
220+
t1 = POINTER(c_int)
221+
t2 = POINTER(c_int)
222+
223+
self.assertIs(t1, t2)
224+
225+
def test_incomplete_pointer_types_not_equal(self):
226+
t1 = POINTER("LP_C")
227+
t2 = POINTER("LP_C")
228+
229+
self.assertIsNot(t1, t2)
230+
231+
def test_pointer_set_type_twice(self):
232+
t1 = POINTER(c_int)
233+
t1.set_type(c_int)
234+
235+
def test_pointer_set_wrong_type(self):
236+
t1 = POINTER(c_int)
237+
with self.assertRaisesRegex(TypeError, "pointer type already set"):
238+
t1.set_type(c_float)
239+
240+
def test_pointer_not_ctypes_type(self):
241+
with self.assertRaisesRegex(TypeError, "must have storage info"):
242+
POINTER(int)
243+
219244

220245
if __name__ == '__main__':
221246
unittest.main()

Modules/_ctypes/_ctypes.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,11 @@ ctype_get_pointer_type(PyObject *self, void *Py_UNUSED(ignored))
580580
if (PyStgInfo_FromType(st, self, &info) < 0) {
581581
return NULL;
582582
}
583-
assert(info); /* Cannot be NULL */
583+
if (!info) {
584+
PyErr_Format(PyExc_TypeError, "%R must have storage info", self);
585+
return NULL;
586+
}
587+
584588
if (info->pointer_type) {
585589
return Py_NewRef(info->pointer_type);
586590
}
@@ -1215,21 +1219,29 @@ PyCPointerType_SetProto(ctypes_state *st, PyObject *self, StgInfo *stginfo, PyOb
12151219
return -1;
12161220
}
12171221
if (!info) {
1218-
PyErr_SetString(PyExc_TypeError,
1219-
"_type_ must have storage info");
1222+
PyErr_Format(PyExc_TypeError, "%R must have storage info", proto);
12201223
return -1;
12211224
}
1222-
if (info->pointer_type) {
1225+
if (info->pointer_type && info->pointer_type != self) {
12231226
PyErr_Format(PyExc_TypeError,
12241227
"pointer type already set: old=%R, new=%R",
12251228
info->pointer_type, self);
12261229
return -1;
12271230
}
1231+
if (stginfo->proto && stginfo->proto != proto) {
1232+
PyErr_Format(PyExc_TypeError,
1233+
"cls type already set: old=%R, new=%R",
1234+
stginfo->proto, proto);
1235+
return -1;
1236+
}
12281237

1229-
Py_INCREF(proto);
1230-
Py_XSETREF(stginfo->proto, proto);
1238+
if (!stginfo->proto) {
1239+
Py_XSETREF(stginfo->proto, Py_NewRef(proto));
1240+
}
12311241

1232-
Py_XSETREF(info->pointer_type, Py_NewRef(self));
1242+
if (!info->pointer_type) {
1243+
Py_XSETREF(info->pointer_type, Py_NewRef(self));
1244+
}
12331245
return 0;
12341246
}
12351247

0 commit comments

Comments
 (0)