Skip to content

Commit 1f6c7c7

Browse files
author
mwh
committed
Apply (my) patch:
[ 526072 ] pickling os.stat results round II structseq's constructors can now take "invisible" fields in a dict. Gave the constructors better error messages. their __reduce__ method puts these fields in a dict. (this is all in aid of getting os.stat_result's to pickle portably) Also fixes [ 526039 ] devious code can crash structseqs Thought needed about how much of this counts as a bugfix. Certainly #526039 needs to be fixed. git-svn-id: http://svn.python.org/projects/python/trunk@25516 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 08ce097 commit 1f6c7c7

1 file changed

Lines changed: 76 additions & 23 deletions

File tree

Objects/structseq.c

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -84,39 +84,79 @@ static PyObject *
8484
structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
8585
{
8686
PyObject *arg = NULL;
87+
PyObject *dict = NULL;
88+
PyObject *ob;
8789
PyStructSequence *res = NULL;
88-
int len, required_len, i;
89-
static char *kwlist[] = {"sequence", 0};
90-
static char msgbuf[128];
90+
int len, min_len, max_len, i;
91+
static char *kwlist[] = {"sequence", "dict", 0};
9192

92-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:structseq",
93-
kwlist, &arg))
93+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
94+
kwlist, &arg, &dict))
9495
return NULL;
9596

96-
if (!PySequence_Check(arg)) {
97-
PyErr_SetString(PyExc_TypeError,
98-
"constructor requires a sequence");
97+
arg = PySequence_Fast(arg, "constructor requires a sequence");
98+
99+
if (!arg) {
99100
return NULL;
100101
}
101102

102-
len = PySequence_Length(arg);
103-
required_len = REAL_SIZE_TP(type);
104-
if (len != required_len) {
105-
PyOS_snprintf(
106-
msgbuf, sizeof(msgbuf),
107-
"constructor takes exactly %d arguments (%d given)",
108-
required_len,
109-
len);
110-
PyErr_SetString(PyExc_TypeError, msgbuf);
103+
if (dict && !PyDict_Check(dict)) {
104+
PyErr_Format(PyExc_TypeError,
105+
"%.500s() takes a dict as second arg, if any",
106+
type->tp_name);
107+
Py_DECREF(arg);
111108
return NULL;
112109
}
113110

111+
len = PySequence_Fast_GET_SIZE(arg);
112+
min_len = VISIBLE_SIZE_TP(type);
113+
max_len = REAL_SIZE_TP(type);
114+
115+
if (min_len != max_len) {
116+
if (len < min_len) {
117+
PyErr_Format(PyExc_TypeError,
118+
"%.500s() takes an at least %d-sequence (%d-sequence given)",
119+
type->tp_name, min_len, len);
120+
Py_DECREF(arg);
121+
return NULL;
122+
}
123+
124+
if (len > max_len) {
125+
PyErr_Format(PyExc_TypeError,
126+
"%.500s() takes an at most %d-sequence (%d-sequence given)",
127+
type->tp_name, max_len, len);
128+
Py_DECREF(arg);
129+
return NULL;
130+
}
131+
}
132+
else {
133+
if (len != min_len) {
134+
PyErr_Format(PyExc_TypeError,
135+
"%.500s() takes a %d-sequence (%d-sequence given)",
136+
type->tp_name, min_len, len);
137+
Py_DECREF(arg);
138+
return NULL;
139+
}
140+
}
141+
114142
res = (PyStructSequence*) PyStructSequence_New(type);
115143
for (i = 0; i < len; ++i) {
116-
/* INCREF???? XXXX */
117-
res->ob_item[i] = PySequence_GetItem(arg, i);
144+
PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
145+
Py_INCREF(v);
146+
res->ob_item[i] = v;
147+
}
148+
for (; i < max_len; ++i) {
149+
if (dict && (ob = PyDict_GetItemString(
150+
dict, type->tp_members[i].name))) {
151+
}
152+
else {
153+
ob = Py_None;
154+
}
155+
Py_INCREF(ob);
156+
res->ob_item[i] = ob;
118157
}
119158

159+
Py_DECREF(arg);
120160
return (PyObject*) res;
121161
}
122162

@@ -192,21 +232,34 @@ static PyObject *
192232
structseq_reduce(PyStructSequence* self)
193233
{
194234
PyObject* tup;
195-
long n_fields;
235+
PyObject* dict;
236+
long n_fields, n_visible_fields;
196237
int i;
197238

198239
n_fields = REAL_SIZE(self);
199-
tup = PyTuple_New(n_fields);
240+
n_visible_fields = VISIBLE_SIZE(self);
241+
tup = PyTuple_New(n_visible_fields);
200242
if (!tup) {
201243
return NULL;
202244
}
203245

204-
for (i = 0; i < n_fields; i++) {
246+
dict = PyDict_New();
247+
if (!dict) {
248+
Py_DECREF(tup);
249+
return NULL;
250+
}
251+
252+
for (i = 0; i < n_visible_fields; i++) {
205253
Py_INCREF(self->ob_item[i]);
206254
PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
207255
}
208256

209-
return Py_BuildValue("(O(O))", self->ob_type, tup);
257+
for (; i < n_fields; i++) {
258+
PyDict_SetItemString(dict, self->ob_type->tp_members[i].name,
259+
self->ob_item[i]);
260+
}
261+
262+
return Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
210263
}
211264

212265
static PySequenceMethods structseq_as_sequence = {

0 commit comments

Comments
 (0)