diff --git a/Lib/ctypes/test/test_structures.py b/Lib/ctypes/test/test_structures.py index 8a4531db936..613163d0cca 100644 --- a/Lib/ctypes/test/test_structures.py +++ b/Lib/ctypes/test/test_structures.py @@ -381,5 +381,35 @@ class PointerMemberTestCase(unittest.TestCase): s.p = None self.failUnlessEqual(s.x, 12345678) +class TestRecursiveStructure(unittest.TestCase): + def test_contains_itself(self): + class Recursive(Structure): + pass + + try: + Recursive._fields_ = [("next", Recursive)] + except AttributeError, details: + self.failUnless("Structure or union cannot contain itself" in + str(details)) + else: + self.fail("Structure or union cannot contain itself") + + + def test_vice_versa(self): + class First(Structure): + pass + class Second(Structure): + pass + + First._fields_ = [("second", Second)] + + try: + Second._fields_ = [("first", First)] + except AttributeError, details: + self.failUnless("_fields_ is final" in + str(details)) + else: + self.fail("AttributeError not raised") + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 0cf1c4bf821..9b8fc274fcc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -70,6 +70,8 @@ Core and builtins Extension Modules ----------------- +- Bug #1598620: A ctypes Structure cannot contain itself. + - Bug #1588217: don't parse "= " as a soft line break in binascii's a2b_qp() function, instead leave it in the string as quopri.decode() does. diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index d701f9ec5d7..8fd9a1e5763 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -339,14 +339,14 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) stgdict = PyType_stgdict(type); if (!stgdict) return -1; + /* If this structure/union is already marked final we cannot assign + _fields_ anymore. */ + if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ PyErr_SetString(PyExc_AttributeError, "_fields_ is final"); return -1; } - /* XXX This should probably be moved to a point when all this - stuff is sucessfully finished. */ - stgdict->flags |= DICTFLAG_FINAL; /* set final */ if (stgdict->ffi_type_pointer.elements) PyMem_Free(stgdict->ffi_type_pointer.elements); @@ -480,5 +480,15 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) stgdict->size = size; stgdict->align = total_align; stgdict->length = len; /* ADD ffi_ofs? */ + + /* We did check that this flag was NOT set above, it must not + have been set until now. */ + if (stgdict->flags & DICTFLAG_FINAL) { + PyErr_SetString(PyExc_AttributeError, + "Structure or union cannot contain itself"); + return -1; + } + stgdict->flags |= DICTFLAG_FINAL; + return MakeAnonFields(type); }