From: Thomas Heller <theller@ctypes.org>
Date: Tue, 15 Jul 2008 17:03:08 +0000 (+0000)
Subject: Issue #3258: Fix an assertion error (in debug build) and a crash (in
X-Git-Tag: v2.6b2~40
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c0b2a807ff9ce7d2c0c83ee808678eb841aa9778;p=python

Issue #3258: Fix an assertion error (in debug build) and a crash (in
release build) when the format string of a pointer to an incomplete
structure is created.
---

diff --git a/Lib/ctypes/test/test_pep3118.py b/Lib/ctypes/test/test_pep3118.py
index cf628d859f..119b0ada87 100644
--- a/Lib/ctypes/test/test_pep3118.py
+++ b/Lib/ctypes/test/test_pep3118.py
@@ -33,6 +33,8 @@ class memoryview(object):
 def normalize(format):
     # Remove current endian specifier and white space from a format
     # string
+    if format is None:
+        return ""
     format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
     return re.sub(r"\s", "", format)
 
@@ -105,6 +107,14 @@ class EmptyStruct(Structure):
 class aUnion(Union):
     _fields_ = [("a", c_int)]
 
+class Incomplete(Structure):
+    pass
+
+class Complete(Structure):
+    pass
+PComplete = POINTER(Complete)
+Complete._fields_ = [("a", c_int)]
+
 ################################################################
 #
 # This table contains format strings as they look on little endian
@@ -162,6 +172,16 @@ native_types = [
     # the pep does't support unions
     (aUnion,                    "B",                    None,           aUnion),
 
+    ## pointer to incomplete structure
+    (Incomplete,                "B",                    None,           Incomplete),
+    (POINTER(Incomplete),       "&B",                   None,           POINTER(Incomplete)),
+
+    # 'Complete' is a structure that starts incomplete, but is completed after the
+    # pointer type to it has been created.
+    (Complete,                  "T{<l:a:}",             None,           Complete),
+    # Unfortunately the pointer format string is not fixed...
+    (POINTER(Complete),         "&B",                   None,           POINTER(Complete)),
+
     ## other
 
     # function signatures are not implemented
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 73542c7a04..9c7355ac9b 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -386,6 +386,11 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
 	}
 	Py_DECREF(result->tp_dict);
 	result->tp_dict = (PyObject *)dict;
+	dict->format = alloc_format_string(NULL, "B");
+	if (dict->format == NULL) {
+		Py_DECREF(result);
+		return NULL;
+	}
 
 	dict->paramfunc = StructUnionType_paramfunc;
 
@@ -907,7 +912,13 @@ PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 	if (proto) {
 		StgDictObject *itemdict = PyType_stgdict(proto);
 		assert(itemdict);
-		stgdict->format = alloc_format_string("&", itemdict->format);
+		/* If itemdict->format is NULL, then this is a pointer to an
+		   incomplete type.  We create a generic format string
+		   'pointer to bytes' in this case.  XXX Better would be to
+		   fix the format string later...
+		*/
+		stgdict->format = alloc_format_string("&",
+			      itemdict->format ? itemdict->format : "B");
 		if (stgdict->format == NULL) {
 			Py_DECREF((PyObject *)stgdict);
 			return NULL;