Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6b70599

Browse files
committed
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.
1 parent ebca9fc commit 6b70599

3 files changed

Lines changed: 19 additions & 6 deletions

File tree

Include/structmember.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ typedef struct PyMemberDef {
6868
#define T_PSTRING_INPLACE 15
6969
#endif /* macintosh */
7070

71+
#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
72+
when the value is NULL, instead of
73+
converting to None. */
74+
7175
/* Flags */
7276
#define READONLY 1
7377
#define RO READONLY /* Shorthand */

Lib/test/test_descr.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -978,19 +978,21 @@ class C1(object):
978978
__slots__ = ['a']
979979
x = C1()
980980
verify(not hasattr(x, "__dict__"))
981-
vereq(x.a, None)
981+
verify(not hasattr(x, "a"))
982982
x.a = 1
983983
vereq(x.a, 1)
984+
x.a = None
985+
veris(x.a, None)
984986
del x.a
985-
vereq(x.a, None)
987+
verify(not hasattr(x, "a"))
986988

987989
class C3(object):
988990
__slots__ = ['a', 'b', 'c']
989991
x = C3()
990992
verify(not hasattr(x, "__dict__"))
991-
verify(x.a is None)
992-
verify(x.b is None)
993-
verify(x.c is None)
993+
verify(not hasattr(x, 'a'))
994+
verify(not hasattr(x, 'b'))
995+
verify(not hasattr(x, 'c'))
994996
x.a = 1
995997
x.b = 2
996998
x.c = 3

Python/structmember.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ PyMember_GetOne(char *addr, PyMemberDef *l)
129129
v = Py_None;
130130
Py_INCREF(v);
131131
break;
132+
case T_OBJECT_EX:
133+
v = *(PyObject **)addr;
134+
if (v == NULL)
135+
PyErr_SetString(PyExc_AttributeError, l->name);
136+
Py_XINCREF(v);
137+
break;
132138
default:
133139
PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
134140
v = NULL;
@@ -175,7 +181,7 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
175181
PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
176182
return -1;
177183
}
178-
if (v == NULL && l->type != T_OBJECT) {
184+
if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) {
179185
PyErr_SetString(PyExc_TypeError,
180186
"can't delete numeric/char attribute");
181187
return -1;
@@ -246,6 +252,7 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
246252
}
247253
break;
248254
case T_OBJECT:
255+
case T_OBJECT_EX:
249256
Py_XINCREF(v);
250257
oldv = *(PyObject **)addr;
251258
*(PyObject **)addr = v;

0 commit comments

Comments
 (0)