Fix SF bug #486144: Uninitialized __slot__ vrbl is None.

There's now a new structmember code, T_OBJECT_EX, which is used for
all __slot__ variables (except __weakref__, which has special behavior
anyway).  This new code raises AttributeError when the variable is
NULL rather than converting NULL to None.
This commit is contained in:
Guido van Rossum 2001-12-04 16:23:42 +00:00
parent ebca9fc1ba
commit 6b70599450
3 changed files with 19 additions and 6 deletions

View file

@ -68,6 +68,10 @@ typedef struct PyMemberDef {
#define T_PSTRING_INPLACE 15 #define T_PSTRING_INPLACE 15
#endif /* macintosh */ #endif /* macintosh */
#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
when the value is NULL, instead of
converting to None. */
/* Flags */ /* Flags */
#define READONLY 1 #define READONLY 1
#define RO READONLY /* Shorthand */ #define RO READONLY /* Shorthand */

View file

@ -978,19 +978,21 @@ def slots():
__slots__ = ['a'] __slots__ = ['a']
x = C1() x = C1()
verify(not hasattr(x, "__dict__")) verify(not hasattr(x, "__dict__"))
vereq(x.a, None) verify(not hasattr(x, "a"))
x.a = 1 x.a = 1
vereq(x.a, 1) vereq(x.a, 1)
x.a = None
veris(x.a, None)
del x.a del x.a
vereq(x.a, None) verify(not hasattr(x, "a"))
class C3(object): class C3(object):
__slots__ = ['a', 'b', 'c'] __slots__ = ['a', 'b', 'c']
x = C3() x = C3()
verify(not hasattr(x, "__dict__")) verify(not hasattr(x, "__dict__"))
verify(x.a is None) verify(not hasattr(x, 'a'))
verify(x.b is None) verify(not hasattr(x, 'b'))
verify(x.c is None) verify(not hasattr(x, 'c'))
x.a = 1 x.a = 1
x.b = 2 x.b = 2
x.c = 3 x.c = 3

View file

@ -129,6 +129,12 @@ PyMember_GetOne(char *addr, PyMemberDef *l)
v = Py_None; v = Py_None;
Py_INCREF(v); Py_INCREF(v);
break; break;
case T_OBJECT_EX:
v = *(PyObject **)addr;
if (v == NULL)
PyErr_SetString(PyExc_AttributeError, l->name);
Py_XINCREF(v);
break;
default: default:
PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
v = NULL; v = NULL;
@ -175,7 +181,7 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
return -1; return -1;
} }
if (v == NULL && l->type != T_OBJECT) { if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"can't delete numeric/char attribute"); "can't delete numeric/char attribute");
return -1; return -1;
@ -246,6 +252,7 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
} }
break; break;
case T_OBJECT: case T_OBJECT:
case T_OBJECT_EX:
Py_XINCREF(v); Py_XINCREF(v);
oldv = *(PyObject **)addr; oldv = *(PyObject **)addr;
*(PyObject **)addr = v; *(PyObject **)addr = v;