33#include "Python.h"
44#include "structmember.h"
55
6+ #include <ctype.h>
7+
8+ /* The *real* layout of a type object when allocated on the heap */
9+ /* XXX Should we publish this in a header file? */
10+ typedef struct {
11+ PyTypeObject type ;
12+ PyNumberMethods as_number ;
13+ PySequenceMethods as_sequence ;
14+ PyMappingMethods as_mapping ;
15+ PyBufferProcs as_buffer ;
16+ PyObject * name , * slots ;
17+ PyMemberDef members [1 ];
18+ } etype ;
19+
620static PyMemberDef type_members [] = {
721 {"__basicsize__" , T_INT , offsetof(PyTypeObject ,tp_basicsize ),READONLY },
822 {"__itemsize__" , T_INT , offsetof(PyTypeObject , tp_itemsize ), READONLY },
@@ -225,32 +239,108 @@ PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
225239
226240/* Helpers for subtyping */
227241
242+ static int
243+ traverse_slots (PyTypeObject * type , PyObject * self , visitproc visit , void * arg )
244+ {
245+ int i , n ;
246+ PyMemberDef * mp ;
247+
248+ n = type -> ob_size ;
249+ mp = ((etype * )type )-> members ;
250+ for (i = 0 ; i < n ; i ++ , mp ++ ) {
251+ if (mp -> type == T_OBJECT_EX ) {
252+ char * addr = (char * )self + mp -> offset ;
253+ PyObject * obj = * (PyObject * * )addr ;
254+ if (obj != NULL ) {
255+ int err = visit (obj , arg );
256+ if (err )
257+ return err ;
258+ }
259+ }
260+ }
261+ return 0 ;
262+ }
263+
228264static int
229265subtype_traverse (PyObject * self , visitproc visit , void * arg )
230266{
231267 PyTypeObject * type , * base ;
232- traverseproc f ;
233- int err ;
268+ traverseproc basetraverse ;
234269
235- /* Find the nearest base with a different tp_traverse */
270+ /* Find the nearest base with a different tp_traverse,
271+ and traverse slots while we're at it */
236272 type = self -> ob_type ;
237- base = type -> tp_base ;
238- while ((f = base -> tp_traverse ) == subtype_traverse ) {
273+ base = type ;
274+ while ((basetraverse = base -> tp_traverse ) == subtype_traverse ) {
275+ if (base -> ob_size ) {
276+ int err = traverse_slots (base , self , visit , arg );
277+ if (err )
278+ return err ;
279+ }
239280 base = base -> tp_base ;
240281 assert (base );
241282 }
242283
243284 if (type -> tp_dictoffset != base -> tp_dictoffset ) {
244285 PyObject * * dictptr = _PyObject_GetDictPtr (self );
245286 if (dictptr && * dictptr ) {
246- err = visit (* dictptr , arg );
287+ int err = visit (* dictptr , arg );
247288 if (err )
248289 return err ;
249290 }
250291 }
251292
252- if (f )
253- return f (self , visit , arg );
293+ if (basetraverse )
294+ return basetraverse (self , visit , arg );
295+ return 0 ;
296+ }
297+
298+ static void
299+ clear_slots (PyTypeObject * type , PyObject * self )
300+ {
301+ int i , n ;
302+ PyMemberDef * mp ;
303+
304+ n = type -> ob_size ;
305+ mp = ((etype * )type )-> members ;
306+ for (i = 0 ; i < n ; i ++ , mp ++ ) {
307+ if (mp -> type == T_OBJECT_EX && !(mp -> flags & READONLY )) {
308+ char * addr = (char * )self + mp -> offset ;
309+ PyObject * obj = * (PyObject * * )addr ;
310+ if (obj != NULL ) {
311+ Py_DECREF (obj );
312+ * (PyObject * * )addr = NULL ;
313+ }
314+ }
315+ }
316+ }
317+
318+ static int
319+ subtype_clear (PyObject * self )
320+ {
321+ PyTypeObject * type , * base ;
322+ inquiry baseclear ;
323+
324+ /* Find the nearest base with a different tp_clear
325+ and clear slots while we're at it */
326+ type = self -> ob_type ;
327+ base = type ;
328+ while ((baseclear = base -> tp_clear ) == subtype_clear ) {
329+ if (base -> ob_size )
330+ clear_slots (base , self );
331+ base = base -> tp_base ;
332+ assert (base );
333+ }
334+
335+ if (type -> tp_dictoffset != base -> tp_dictoffset ) {
336+ PyObject * * dictptr = _PyObject_GetDictPtr (self );
337+ if (dictptr && * dictptr ) {
338+ PyDict_Clear (* dictptr );
339+ }
340+ }
341+
342+ if (baseclear )
343+ return baseclear (self );
254344 return 0 ;
255345}
256346
@@ -329,41 +419,24 @@ static void
329419subtype_dealloc (PyObject * self )
330420{
331421 PyTypeObject * type , * base ;
332- destructor f ;
422+ destructor basedealloc ;
333423
334424 /* This exists so we can DECREF self->ob_type */
335425
336426 if (call_finalizer (self ) < 0 )
337427 return ;
338428
339- /* Find the nearest base with a different tp_dealloc */
429+ /* Find the nearest base with a different tp_dealloc
430+ and clear slots while we're at it */
340431 type = self -> ob_type ;
341- base = type -> tp_base ;
342- while ((f = base -> tp_dealloc ) == subtype_dealloc ) {
432+ base = type ;
433+ while ((basedealloc = base -> tp_dealloc ) == subtype_dealloc ) {
434+ if (base -> ob_size )
435+ clear_slots (base , self );
343436 base = base -> tp_base ;
344437 assert (base );
345438 }
346439
347- /* Clear __slots__ variables */
348- if (type -> tp_basicsize != base -> tp_basicsize &&
349- type -> tp_itemsize == 0 )
350- {
351- char * addr = ((char * )self );
352- char * p = addr + base -> tp_basicsize ;
353- char * q = addr + type -> tp_basicsize ;
354- for (; p < q ; p += sizeof (PyObject * )) {
355- PyObject * * pp ;
356- if (p == addr + type -> tp_dictoffset ||
357- p == addr + type -> tp_weaklistoffset )
358- continue ;
359- pp = (PyObject * * )p ;
360- if (* pp != NULL ) {
361- Py_DECREF (* pp );
362- * pp = NULL ;
363- }
364- }
365- }
366-
367440 /* If we added a dict, DECREF it */
368441 if (type -> tp_dictoffset && !base -> tp_dictoffset ) {
369442 PyObject * * dictptr = _PyObject_GetDictPtr (self );
@@ -385,8 +458,8 @@ subtype_dealloc(PyObject *self)
385458 _PyObject_GC_UNTRACK (self );
386459
387460 /* Call the base tp_dealloc() */
388- assert (f );
389- f (self );
461+ assert (basedealloc );
462+ basedealloc (self );
390463
391464 /* Can't reference self beyond this point */
392465 if (type -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
@@ -396,16 +469,6 @@ subtype_dealloc(PyObject *self)
396469
397470staticforward PyTypeObject * solid_base (PyTypeObject * type );
398471
399- typedef struct {
400- PyTypeObject type ;
401- PyNumberMethods as_number ;
402- PySequenceMethods as_sequence ;
403- PyMappingMethods as_mapping ;
404- PyBufferProcs as_buffer ;
405- PyObject * name , * slots ;
406- PyMemberDef members [1 ];
407- } etype ;
408-
409472/* type test with subclassing support */
410473
411474int
@@ -890,6 +953,33 @@ static PyMethodDef bozo_ml = {"__getstate__", bozo_func, METH_VARARGS};
890953
891954static PyObject * bozo_obj = NULL ;
892955
956+ static int
957+ valid_identifier (PyObject * s )
958+ {
959+ char * p ;
960+ int i , n ;
961+
962+ if (!PyString_Check (s )) {
963+ PyErr_SetString (PyExc_TypeError ,
964+ "__slots__ must be strings" );
965+ return 0 ;
966+ }
967+ p = PyString_AS_STRING (s );
968+ n = PyString_GET_SIZE (s );
969+ /* We must reject an empty name. As a hack, we bump the
970+ length to 1 so that the loop will balk on the trailing \0. */
971+ if (n == 0 )
972+ n = 1 ;
973+ for (i = 0 ; i < n ; i ++ , p ++ ) {
974+ if (!(i == 0 ? isalpha (* p ) : isalnum (* p )) && * p != '_' ) {
975+ PyErr_SetString (PyExc_TypeError ,
976+ "__slots__ must be identifiers" );
977+ return 0 ;
978+ }
979+ }
980+ return 1 ;
981+ }
982+
893983static PyObject *
894984type_new (PyTypeObject * metatype , PyObject * args , PyObject * kwds )
895985{
@@ -1004,13 +1094,10 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
10041094 return NULL ;
10051095 }
10061096 for (i = 0 ; i < nslots ; i ++ ) {
1007- if (!PyString_Check (PyTuple_GET_ITEM (slots , i ))) {
1008- PyErr_SetString (PyExc_TypeError ,
1009- "__slots__ must be a sequence of strings" );
1097+ if (!valid_identifier (PyTuple_GET_ITEM (slots , i ))) {
10101098 Py_DECREF (slots );
10111099 return NULL ;
10121100 }
1013- /* XXX Check against null bytes in name */
10141101 }
10151102 }
10161103 if (slots != NULL ) {
@@ -1145,6 +1232,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
11451232 if (base -> tp_weaklistoffset == 0 &&
11461233 strcmp (mp -> name , "__weakref__" ) == 0 ) {
11471234 mp -> type = T_OBJECT ;
1235+ mp -> flags = READONLY ;
11481236 type -> tp_weaklistoffset = slotoffset ;
11491237 }
11501238 slotoffset += sizeof (PyObject * );
@@ -1194,7 +1282,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
11941282 if (type -> tp_flags & Py_TPFLAGS_HAVE_GC ) {
11951283 type -> tp_free = PyObject_GC_Del ;
11961284 type -> tp_traverse = subtype_traverse ;
1197- type -> tp_clear = base -> tp_clear ;
1285+ type -> tp_clear = subtype_clear ;
11981286 }
11991287 else
12001288 type -> tp_free = PyObject_Del ;
0 commit comments