pyke/pyke.[ch]: Make type skeleton structures be read-only.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 20 Oct 2019 20:18:08 +0000 (21:18 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 11:44:14 +0000 (12:44 +0100)
We couldn't do this before because `INITTYPE_META' would write the
direct superclass to the `tp_base' slot in the skeleton before calling
`inittype'.  To make this work, then, we adjust `inittype' to take the
direct superclass as an extra argument and plug it into the newly
created heap-type; and `INITTYPE_META' needs adjusting to pass this
argument rather than trying to write to the skeleton directly.

Of course, then we need to actually mark the type skeletons as `const'.

mapping.c
pyke.c
pyke.h

index 7080ca5..e97fcb0 100644 (file)
--- a/mapping.c
+++ b/mapping.c
@@ -54,7 +54,7 @@ static PyObject *itemiter_pynext(PyObject *me)
   return (rc);
 }
 
-static PyTypeObject itemiter_pytype_skel = {
+static const PyTypeObject itemiter_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
   "ItemIter",                          /* @tp_name@ */
   sizeof(iter_pyobj),                  /* @tp_basicsize@ */
@@ -112,7 +112,7 @@ static PyObject *valiter_pynext(PyObject *me)
   return (rc);
 }
 
-static PyTypeObject valiter_pytype_skel = {
+static const PyTypeObject valiter_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
   "ValueIter",                         /* @tp_name@ */
   sizeof(iter_pyobj),                  /* @tp_basicsize@ */
diff --git a/pyke.c b/pyke.c
index b462a1f..f19c9e4 100644 (file)
--- a/pyke.c
+++ b/pyke.c
@@ -218,7 +218,6 @@ void *newtype(PyTypeObject *metaty,
     (PyHeapTypeObject *)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty, 0));
   if (!skel) skel = &emptytype;
   memcpy(ty, skel, sizeof(*skel));
-  if (ty->ht_type.tp_base) Py_INCREF(ty->ht_type.tp_base);
 #define COPY(blah) do {                                                        \
     if (ty->ht_type.tp_as_##blah) {                                    \
       memcpy(&ty->as_##blah,                                           \
@@ -249,9 +248,11 @@ void typeready(PyTypeObject *ty)
   PyDict_SetItemString(ty->tp_dict, "__module__", modname);
 }
 
-PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta)
+PyTypeObject *inittype(const PyTypeObject *tyskel,
+                      PyTypeObject *base, PyTypeObject *meta)
 {
   PyTypeObject *ty = newtype(meta, tyskel, 0);
+  if (base) { ty->tp_base = base; Py_INCREF(base); }
   ty->tp_flags |= Py_TPFLAGS_HEAPTYPE;
   typeready(ty);
   return (ty);
diff --git a/pyke.h b/pyke.h
index 3076bb5..138a9fb 100644 (file)
--- a/pyke.h
+++ b/pyke.h
@@ -208,11 +208,11 @@ extern void *newtype(PyTypeObject */*meta*/,
 extern void typeready(PyTypeObject *);
   /* The type object is now ready to be used. */
 
-extern PyTypeObject *inittype(PyTypeObject */*skel*/,
+extern PyTypeObject *inittype(const PyTypeObject */*skel*/,
+                             PyTypeObject */*base*/,
                              PyTypeObject */*meta*/);
   /* All-in-one function to construct a working type from a type skeleton
-   * SKEL, with metaclass META.  The caller is expected to have filled in the
-   * direct superclass in SKEL->tp_base.
+   * SKEL, with known base type BASE (null for `object') and metaclass.
    */
 
 /* Alias for built-in types, to fit in with Pyke naming conventions. */
@@ -220,8 +220,7 @@ extern PyTypeObject *inittype(PyTypeObject */*skel*/,
 #define type_pytype &PyType_Type
 
 #define INITTYPE_META(ty, base, meta) do {                             \
-  ty##_pytype_skel.tp_base = base##_pytype;                            \
-  ty##_pytype = inittype(&ty##_pytype_skel, meta##_pytype);            \
+  ty##_pytype = inittype(&ty##_pytype_skel, base##_pytype, meta##_pytype); \
 } while (0)
 #define INITTYPE(ty, base) INITTYPE_META(ty, base, type)
   /* Macros to initialize a type from its skeleton. */