From 30b61b51e05d2d43e8e2e783b0a9df738535423b Mon Sep 17 00:00:00 2001 From: Oren Milman Date: Sun, 17 Sep 2017 13:45:38 +0300 Subject: [PATCH] bpo-31490: Fix an assertion failure in ctypes in case an _anonymous_ attr is defined only outside _fields_. (#3615) --- Lib/ctypes/test/test_anon.py | 13 +++++++++++++ .../2017-09-16-13-32-35.bpo-31490.r7m2sj.rst | 3 +++ Modules/_ctypes/stgdict.c | 10 +++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-09-16-13-32-35.bpo-31490.r7m2sj.rst diff --git a/Lib/ctypes/test/test_anon.py b/Lib/ctypes/test/test_anon.py index d892b59898..d378392ebe 100644 --- a/Lib/ctypes/test/test_anon.py +++ b/Lib/ctypes/test/test_anon.py @@ -1,4 +1,5 @@ import unittest +import test.support from ctypes import * class AnonTest(unittest.TestCase): @@ -35,6 +36,18 @@ class AnonTest(unittest.TestCase): {"_fields_": [], "_anonymous_": ["x"]})) + @test.support.cpython_only + def test_issue31490(self): + # There shouldn't be an assertion failure in case the class has an + # attribute whose name is specified in _anonymous_ but not in _fields_. + + # AttributeError: 'x' is specified in _anonymous_ but not in _fields_ + with self.assertRaises(AttributeError): + class Name(Structure): + _fields_ = [] + _anonymous_ = ["x"] + x = 42 + def test_nested(self): class ANON_S(Structure): _fields_ = [("a", c_int)] diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-16-13-32-35.bpo-31490.r7m2sj.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-16-13-32-35.bpo-31490.r7m2sj.rst new file mode 100644 index 0000000000..d95e825f13 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-16-13-32-35.bpo-31490.r7m2sj.rst @@ -0,0 +1,3 @@ +Fix an assertion failure in `ctypes` class definition, in case the class has +an attribute whose name is specified in ``_anonymous_`` but not in +``_fields_``. Patch by Oren Milman. diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index 3496c5706c..b66c6ecd2f 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -302,7 +302,15 @@ MakeAnonFields(PyObject *type) Py_DECREF(anon_names); return -1; } - assert(Py_TYPE(descr) == &PyCField_Type); + if (Py_TYPE(descr) != &PyCField_Type) { + PyErr_Format(PyExc_AttributeError, + "'%U' is specified in _anonymous_ but not in " + "_fields_", + fname); + Py_DECREF(anon_names); + Py_DECREF(descr); + return -1; + } descr->anonymous = 1; /* descr is in the field descriptor. */ -- 2.40.0