From: Michael W. Hudson <mwh@python.net>
Date: Wed, 6 Mar 2002 17:07:49 +0000 (+0000)
Subject: Apply (my) patch:
X-Git-Tag: v2.3c1~6570
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ce358e3015bc8cafdf949dee624b01f4a38bfad2;p=python

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.
---

diff --git a/Objects/structseq.c b/Objects/structseq.c
index e5f8e09cf4..9228e0fdf5 100644
--- a/Objects/structseq.c
+++ b/Objects/structseq.c
@@ -84,39 +84,79 @@ static PyObject *
 structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
 	PyObject *arg = NULL;
+	PyObject *dict = NULL;
+	PyObject *ob;
 	PyStructSequence *res = NULL;
-	int len, required_len, i;
-	static char *kwlist[] = {"sequence", 0};
-	static char msgbuf[128];
+	int len, min_len, max_len, i;
+	static char *kwlist[] = {"sequence", "dict", 0};
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:structseq", 
-					 kwlist, &arg))
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq", 
+					 kwlist, &arg, &dict))
 		return NULL;
 
-	if (!PySequence_Check(arg)) {
-		PyErr_SetString(PyExc_TypeError,
-				"constructor requires a sequence");
+	arg = PySequence_Fast(arg, "constructor requires a sequence");
+
+	if (!arg) {				
 		return NULL;
 	}
 
-	len = PySequence_Length(arg);
-	required_len = REAL_SIZE_TP(type);
-	if (len != required_len) {
-		PyOS_snprintf(
-			msgbuf, sizeof(msgbuf),
-			"constructor takes exactly %d arguments (%d given)",
-			required_len,
-			len);
-		PyErr_SetString(PyExc_TypeError, msgbuf);
+	if (dict && !PyDict_Check(dict)) {
+		PyErr_Format(PyExc_TypeError, 
+			     "%.500s() takes a dict as second arg, if any",
+			     type->tp_name);
+		Py_DECREF(arg);
 		return NULL;
 	}
 
+	len = PySequence_Fast_GET_SIZE(arg);
+	min_len = VISIBLE_SIZE_TP(type);
+	max_len = REAL_SIZE_TP(type);
+
+	if (min_len != max_len) {
+		if (len < min_len) {
+			PyErr_Format(PyExc_TypeError, 
+	       "%.500s() takes an at least %d-sequence (%d-sequence given)",
+				     type->tp_name, min_len, len);
+			Py_DECREF(arg);
+			return NULL;
+		}
+
+		if (len > max_len) {
+			PyErr_Format(PyExc_TypeError, 
+	       "%.500s() takes an at most %d-sequence (%d-sequence given)",
+				     type->tp_name, max_len, len);
+			Py_DECREF(arg);
+			return NULL;
+		}
+	} 
+	else {
+		if (len != min_len) {
+			PyErr_Format(PyExc_TypeError, 
+	       "%.500s() takes a %d-sequence (%d-sequence given)",
+				     type->tp_name, min_len, len);
+			Py_DECREF(arg);
+			return NULL;
+		}
+	}
+
 	res = (PyStructSequence*) PyStructSequence_New(type);
 	for (i = 0; i < len; ++i) {
-		/* INCREF???? XXXX */
-		res->ob_item[i] = PySequence_GetItem(arg, i);
+		PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
+		Py_INCREF(v);
+		res->ob_item[i] = v;
+	}
+	for (; i < max_len; ++i) {
+		if (dict && (ob = PyDict_GetItemString(
+			dict, type->tp_members[i].name))) {
+		}
+		else {
+			ob = Py_None;
+		}
+		Py_INCREF(ob);
+		res->ob_item[i] = ob;
 	}
 	
+	Py_DECREF(arg);
 	return (PyObject*) res;
 }
 
@@ -192,21 +232,34 @@ static PyObject *
 structseq_reduce(PyStructSequence* self)
 {
 	PyObject* tup;
-	long n_fields;
+	PyObject* dict;
+	long n_fields, n_visible_fields;
 	int i;
 	
 	n_fields = REAL_SIZE(self);
-	tup = PyTuple_New(n_fields);
+	n_visible_fields = VISIBLE_SIZE(self);
+	tup = PyTuple_New(n_visible_fields);
 	if (!tup) {
 		return NULL;
 	}
 
-	for (i = 0; i < n_fields; i++) {
+	dict = PyDict_New();
+	if (!dict) {
+		Py_DECREF(tup);
+		return NULL;
+	}
+
+	for (i = 0; i < n_visible_fields; i++) {
 		Py_INCREF(self->ob_item[i]);
 		PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
 	}
 	
-	return Py_BuildValue("(O(O))", self->ob_type, tup);
+	for (; i < n_fields; i++) {
+		PyDict_SetItemString(dict, self->ob_type->tp_members[i].name,
+				     self->ob_item[i]);
+	}
+
+	return Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
 }
 
 static PySequenceMethods structseq_as_sequence = {