mirror of
https://github.com/python/cpython.git
synced 2025-10-17 12:18:23 +00:00
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:
parent
ebca9fc1ba
commit
6b70599450
3 changed files with 19 additions and 6 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue