[Python-checkins] r52452 - in python/trunk: Lib/test/test_structmembers.py Misc/ACKS Misc/NEWS Modules/_testcapimodule.c Python/structmember.c

martin.v.loewis python-checkins at python.org
Fri Oct 27 08:16:32 CEST 2006


Author: martin.v.loewis
Date: Fri Oct 27 08:16:31 2006
New Revision: 52452

Added:
   python/trunk/Lib/test/test_structmembers.py   (contents, props changed)
Modified:
   python/trunk/Misc/ACKS
   python/trunk/Misc/NEWS
   python/trunk/Modules/_testcapimodule.c
   python/trunk/Python/structmember.c
Log:
Patch #1549049: Rewrite type conversion in structmember.
Fixes #1545696 and #1566140. Will backport to 2.5.


Added: python/trunk/Lib/test/test_structmembers.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/test/test_structmembers.py	Fri Oct 27 08:16:31 2006
@@ -0,0 +1,80 @@
+from _testcapi import test_structmembersType, \
+    CHAR_MAX, CHAR_MIN, UCHAR_MAX, \
+    SHRT_MAX, SHRT_MIN, USHRT_MAX, \
+    INT_MAX, INT_MIN, UINT_MAX, \
+    LONG_MAX, LONG_MIN, ULONG_MAX
+
+import warnings, exceptions, unittest, test.test_warnings
+from test import test_support
+
+ts=test_structmembersType(1,2,3,4,5,6,7,8,9.99999,10.1010101010)
+
+class ReadWriteTests(unittest.TestCase):
+    def test_types(self):
+        ts.T_BYTE=CHAR_MAX
+        self.assertEquals(ts.T_BYTE, CHAR_MAX)
+        ts.T_BYTE=CHAR_MIN
+        self.assertEquals(ts.T_BYTE, CHAR_MIN)
+        ts.T_UBYTE=UCHAR_MAX
+        self.assertEquals(ts.T_UBYTE, UCHAR_MAX)
+
+        ts.T_SHORT=SHRT_MAX
+        self.assertEquals(ts.T_SHORT, SHRT_MAX)
+        ts.T_SHORT=SHRT_MIN
+        self.assertEquals(ts.T_SHORT, SHRT_MIN)
+        ts.T_USHORT=USHRT_MAX
+        self.assertEquals(ts.T_USHORT, USHRT_MAX)
+
+        ts.T_INT=INT_MAX
+        self.assertEquals(ts.T_INT, INT_MAX)
+        ts.T_INT=INT_MIN
+        self.assertEquals(ts.T_INT, INT_MIN)
+        ts.T_UINT=UINT_MAX
+        self.assertEquals(ts.T_UINT, UINT_MAX)
+
+        ts.T_LONG=LONG_MAX
+        self.assertEquals(ts.T_LONG, LONG_MAX)
+        ts.T_LONG=LONG_MIN
+        self.assertEquals(ts.T_LONG, LONG_MIN)
+        ts.T_ULONG=ULONG_MAX
+        self.assertEquals(ts.T_ULONG, ULONG_MAX)
+
+class TestWarnings(test.test_warnings.TestModule):
+    def has_warned(self):
+        self.assertEqual(test.test_warnings.msg.category,
+                         exceptions.RuntimeWarning.__name__)
+        
+    def test_byte_max(self):
+        ts.T_BYTE=CHAR_MAX+1
+        self.has_warned()
+        
+    def test_byte_min(self):
+        ts.T_BYTE=CHAR_MIN-1
+        self.has_warned()
+
+    def test_ubyte_max(self):
+        ts.T_UBYTE=UCHAR_MAX+1
+        self.has_warned()
+
+    def test_short_max(self):
+        ts.T_SHORT=SHRT_MAX+1
+        self.has_warned()
+
+    def test_short_min(self):
+        ts.T_SHORT=SHRT_MIN-1
+        self.has_warned()
+
+    def test_ushort_max(self):
+        ts.T_USHORT=USHRT_MAX+1
+        self.has_warned()
+
+        
+
+def test_main(verbose=None):
+    test_support.run_unittest(
+        ReadWriteTests,
+        TestWarnings
+        )
+
+if __name__ == "__main__":
+    test_main(verbose=True)

Modified: python/trunk/Misc/ACKS
==============================================================================
--- python/trunk/Misc/ACKS	(original)
+++ python/trunk/Misc/ACKS	Fri Oct 27 08:16:31 2006
@@ -633,6 +633,7 @@
 Bill Tutt
 Doobee R. Tzeck
 Lionel Ulmer
+Roger Upole
 Michael Urman
 Hector Urtubia
 Dmitry Vasiliev

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Fri Oct 27 08:16:31 2006
@@ -12,6 +12,9 @@
 Core and builtins
 -----------------
 
+- Patch #1549049: Support long values in structmember, issue warnings
+  if the assigned value for structmember fields gets truncated.
+
 - Update the peephole optimizer to remove more dead code (jumps after returns)
   and inline unconditional jumps to returns.
 

Modified: python/trunk/Modules/_testcapimodule.c
==============================================================================
--- python/trunk/Modules/_testcapimodule.c	(original)
+++ python/trunk/Modules/_testcapimodule.c	Fri Oct 27 08:16:31 2006
@@ -6,6 +6,8 @@
  */
 
 #include "Python.h"
+#include <values.h>
+#include "structmember.h"
 
 #ifdef WITH_THREAD
 #include "pythread.h"
@@ -35,13 +37,13 @@
    platforms have these hardcoded.  Better safe than sorry.
 */
 static PyObject*
-sizeof_error(const char* fatname, const char* typename,
+sizeof_error(const char* fatname, const char* typname,
         int expected, int got)
 {
 	char buf[1024];
 	PyOS_snprintf(buf, sizeof(buf),
 		"%.200s #define == %d but sizeof(%.200s) == %d",
-		fatname, expected, typename, got);
+		fatname, expected, typname, got);
 	PyErr_SetString(TestError, buf);
 	return (PyObject*)NULL;
 }
@@ -615,7 +617,7 @@
 {
 	PyObject *rc;
 	PyGILState_STATE s = PyGILState_Ensure();
-	rc = PyObject_CallFunction(callable, "");
+	rc = PyObject_CallFunction((PyObject *)callable, "");
 	Py_XDECREF(rc);
 	PyGILState_Release(s);
 }
@@ -756,6 +758,105 @@
 
 #define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);}
 
+typedef struct {
+	char byte_member;
+	unsigned char ubyte_member;
+	short short_member;
+	unsigned short ushort_member;
+	int int_member;
+	unsigned int uint_member;
+	long long_member;
+	unsigned long ulong_member;
+	float float_member;
+	double double_member;
+} all_structmembers;
+
+typedef struct {
+    PyObject_HEAD
+	all_structmembers structmembers;
+} test_structmembers;
+
+static struct PyMemberDef test_members[] = {
+	{"T_BYTE", T_BYTE, offsetof(test_structmembers, structmembers.byte_member), 0, NULL},
+	{"T_UBYTE", T_UBYTE, offsetof(test_structmembers, structmembers.ubyte_member), 0, NULL},
+	{"T_SHORT", T_SHORT, offsetof(test_structmembers, structmembers.short_member), 0, NULL},
+	{"T_USHORT", T_USHORT, offsetof(test_structmembers, structmembers.ushort_member), 0, NULL},
+	{"T_INT", T_INT, offsetof(test_structmembers, structmembers.int_member), 0, NULL},
+	{"T_UINT", T_UINT, offsetof(test_structmembers, structmembers.uint_member), 0, NULL},
+	{"T_LONG", T_LONG, offsetof(test_structmembers, structmembers.long_member), 0, NULL},
+	{"T_ULONG", T_ULONG, offsetof(test_structmembers, structmembers.ulong_member), 0, NULL},
+	{"T_FLOAT", T_FLOAT, offsetof(test_structmembers, structmembers.float_member), 0, NULL},
+	{"T_DOUBLE", T_DOUBLE, offsetof(test_structmembers, structmembers.double_member), 0, NULL},
+	{NULL}
+};
+
+
+static PyObject *test_structmembers_new(PyTypeObject *type, PyObject *args, PyObject *kwargs){
+	static char *keywords[]={"T_BYTE", "T_UBYTE", "T_SHORT", "T_USHORT", "T_INT", "T_UINT",
+		"T_LONG", "T_ULONG", "T_FLOAT", "T_DOUBLE", NULL};
+	test_structmembers *ob=PyObject_New(test_structmembers, type);
+	if (ob==NULL)
+		return NULL;
+	memset(&ob->structmembers, 0, sizeof(all_structmembers));
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|bBhHiIlkfd", keywords,
+		&ob->structmembers.byte_member, &ob->structmembers.ubyte_member,
+		&ob->structmembers.short_member, &ob->structmembers.ushort_member,
+		&ob->structmembers.int_member, &ob->structmembers.uint_member, 
+		&ob->structmembers.long_member, &ob->structmembers.ulong_member,
+		&ob->structmembers.float_member, &ob->structmembers.double_member)){
+		Py_DECREF(ob);
+		return NULL;
+		}
+	return (PyObject *)ob;
+}
+
+static void test_structmembers_free(PyObject *ob){
+	PyObject_FREE(ob);
+}
+
+static PyTypeObject test_structmembersType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+	"test_structmembersType",
+	sizeof(test_structmembers),	/* tp_basicsize */
+	0,				/* tp_itemsize */
+	test_structmembers_free,	/* destructor tp_dealloc */
+	0,				/* tp_print */
+	0,				/* tp_getattr */
+	0,				/* tp_setattr */
+	0,				/* tp_compare */
+	0,				/* tp_repr */
+	0,				/* tp_as_number */
+	0,				/* tp_as_sequence */
+	0,				/* tp_as_mapping */
+	0,				/* tp_hash */
+	0,				/* tp_call */
+	0,				/* tp_str */
+	PyObject_GenericGetAttr,
+	PyObject_GenericSetAttr,
+	0,				/* tp_as_buffer */
+	0,				/* tp_flags */
+	"Type containing all structmember types",
+	0,				/* traverseproc tp_traverse */
+	0,				/* tp_clear */
+	0,				/* tp_richcompare */
+	0,				/* tp_weaklistoffset */
+	0,				/* tp_iter */
+	0,				/* tp_iternext */
+	0,				/* tp_methods */
+	test_members,	/* tp_members */
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	test_structmembers_new,			/* tp_new */
+};
+
+
 PyMODINIT_FUNC
 init_testcapi(void)
 {
@@ -765,16 +866,28 @@
 	if (m == NULL)
 		return;
 
+	test_structmembersType.ob_type=&PyType_Type;
+	Py_INCREF(&test_structmembersType);
+	PyModule_AddObject(m, "test_structmembersType", (PyObject *)&test_structmembersType);
+
+	PyModule_AddObject(m, "CHAR_MAX", PyInt_FromLong(CHAR_MAX));
+	PyModule_AddObject(m, "CHAR_MIN", PyInt_FromLong(CHAR_MIN));
 	PyModule_AddObject(m, "UCHAR_MAX", PyInt_FromLong(UCHAR_MAX));
+	PyModule_AddObject(m, "SHRT_MAX", PyInt_FromLong(SHRT_MAX));
+	PyModule_AddObject(m, "SHRT_MIN", PyInt_FromLong(SHRT_MIN));
 	PyModule_AddObject(m, "USHRT_MAX", PyInt_FromLong(USHRT_MAX));
+	PyModule_AddObject(m, "INT_MAX",  PyLong_FromLong(INT_MAX));
+	PyModule_AddObject(m, "INT_MIN",  PyLong_FromLong(INT_MIN));
 	PyModule_AddObject(m, "UINT_MAX",  PyLong_FromUnsignedLong(UINT_MAX));
-	PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX));
-	PyModule_AddObject(m, "INT_MIN", PyInt_FromLong(INT_MIN));
-	PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN));
-	PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyInt_FromSsize_t(PY_SSIZE_T_MIN));
-	PyModule_AddObject(m, "INT_MAX", PyInt_FromLong(INT_MAX));
 	PyModule_AddObject(m, "LONG_MAX", PyInt_FromLong(LONG_MAX));
+	PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN));
+	PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX));
+	PyModule_AddObject(m, "FLT_MAX", PyFloat_FromDouble(FLT_MAX));
+	PyModule_AddObject(m, "FLT_MIN", PyFloat_FromDouble(FLT_MIN));
+	PyModule_AddObject(m, "DBL_MAX", PyFloat_FromDouble(DBL_MAX));
+	PyModule_AddObject(m, "DBL_MIN", PyFloat_FromDouble(DBL_MIN));
 	PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyInt_FromSsize_t(PY_SSIZE_T_MAX));
+	PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyInt_FromSsize_t(PY_SSIZE_T_MIN));
 
 	TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
 	Py_INCREF(TestError);

Modified: python/trunk/Python/structmember.c
==============================================================================
--- python/trunk/Python/structmember.c	(original)
+++ python/trunk/Python/structmember.c	Fri Oct 27 08:16:31 2006
@@ -62,29 +62,28 @@
 	addr += l->offset;
 	switch (l->type) {
 	case T_BYTE:
-		v = PyInt_FromLong(
-			(long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80));
+		v = PyInt_FromLong(*(char*)addr);
 		break;
 	case T_UBYTE:
-		v = PyInt_FromLong((long) *(char*)addr & 0xff);
+		v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
 		break;
 	case T_SHORT:
-		v = PyInt_FromLong((long) *(short*)addr);
+		v = PyInt_FromLong(*(short*)addr);
 		break;
 	case T_USHORT:
-		v = PyInt_FromLong((long) *(unsigned short*)addr);
+		v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
 		break;
 	case T_INT:
-		v = PyInt_FromLong((long) *(int*)addr);
+		v = PyInt_FromLong(*(int*)addr);
 		break;
 	case T_UINT:
-		v = PyInt_FromLong((long) *(unsigned int*)addr);
+		v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
 		break;
 	case T_LONG:
 		v = PyInt_FromLong(*(long*)addr);
 		break;
 	case T_ULONG:
-		v = PyLong_FromDouble((double) *(unsigned long*)addr);
+		v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
 		break;
 	case T_FLOAT:
 		v = PyFloat_FromDouble((double)*(float*)addr);
@@ -175,68 +174,107 @@
 	}
 	addr += l->offset;
 	switch (l->type) {
-	case T_BYTE:
-	case T_UBYTE:
-		if (!PyInt_Check(v)) {
-			PyErr_BadArgument();
+	case T_BYTE:{
+		long long_val;
+		long_val = PyInt_AsLong(v);
+		if ((long_val == -1) && PyErr_Occurred())
 			return -1;
-		}
-		*(char*)addr = (char) PyInt_AsLong(v);
+		/* XXX: For compatibility, only warn about truncations
+		   for now. */
+		if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to char");
+		*(char*)addr = (char)long_val;
 		break;
-	case T_SHORT:
-	case T_USHORT:
-		if (!PyInt_Check(v)) {
-			PyErr_BadArgument();
-			return -1;
 		}
-		*(short*)addr = (short) PyInt_AsLong(v);
-		break;
-	case T_UINT:
-	case T_INT:
-		if (!PyInt_Check(v)) {
-			PyErr_BadArgument();
+	case T_UBYTE:{
+		long long_val;
+		long_val = PyInt_AsLong(v);
+		if ((long_val == -1) && PyErr_Occurred())
 			return -1;
-		}
-		*(int*)addr = (int) PyInt_AsLong(v);
+		if ((long_val > UCHAR_MAX) || (long_val < 0))
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned char");
+		*(unsigned char*)addr = (unsigned char)long_val;
 		break;
-	case T_LONG:
-		if (!PyInt_Check(v)) {
-			PyErr_BadArgument();
+		}
+	case T_SHORT:{
+		long long_val;
+		long_val = PyInt_AsLong(v);
+		if ((long_val == -1) && PyErr_Occurred())
 			return -1;
+		if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to short");
+		*(short*)addr = (short)long_val;
+		break;
 		}
-		*(long*)addr = PyInt_AsLong(v);
+	case T_USHORT:{
+		long long_val;
+		long_val = PyInt_AsLong(v);
+		if ((long_val == -1) && PyErr_Occurred())
+			return -1;
+		if ((long_val > USHRT_MAX) || (long_val < 0))
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned short");
+		*(unsigned short*)addr = (unsigned short)long_val;
 		break;
-	case T_ULONG:
-		if (PyInt_Check(v))
-			*(long*)addr = PyInt_AsLong(v);
-		else if (PyLong_Check(v))
-			*(long*)addr = PyLong_AsLong(v);
-		else {
-			PyErr_BadArgument();
+		}
+  	case T_INT:{
+		long long_val;
+		long_val = PyInt_AsLong(v);
+		if ((long_val == -1) && PyErr_Occurred())
 			return -1;
+		if ((long_val > INT_MAX) || (long_val < INT_MIN))
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to int");
+		*(int *)addr = (int)long_val;
+		break;
+		}
+	case T_UINT:{
+		unsigned long ulong_val;
+		ulong_val = PyLong_AsUnsignedLong(v);
+		if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) {
+			/* XXX: For compatibility, accept negative int values
+			   as well. */
+			PyErr_Clear();
+			ulong_val = PyLong_AsLong(v);
+			if ((ulong_val == (unsigned int)-1) && PyErr_Occurred())
+				return -1;
+			PyErr_Warn(PyExc_RuntimeWarning, "Writing negative value into unsigned field");
+		}
+		if (ulong_val > UINT_MAX)
+			PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned int");
+		*(unsigned int *)addr = (unsigned int)ulong_val;
+		break;
+		}
+	case T_LONG:{
+		*(long*)addr = PyLong_AsLong(v);
+		if ((*(long*)addr == -1) && PyErr_Occurred())
+			return -1;
+		break;
+		}
+	case T_ULONG:{
+		*(unsigned long*)addr = PyLong_AsUnsignedLong(v);
+		if ((*(unsigned long*)addr == (unsigned long)-1)
+		    && PyErr_Occurred()) {
+			/* XXX: For compatibility, accept negative int values
+			   as well. */
+			PyErr_Clear();
+			*(unsigned long*)addr = PyLong_AsLong(v);
+			if ((*(unsigned long*)addr == (unsigned int)-1) && PyErr_Occurred())
+				return -1;
+			PyErr_Warn(PyExc_RuntimeWarning, "Writing negative value into unsigned field");
 		}
 		break;
-	case T_FLOAT:
-		if (PyInt_Check(v))
-			*(float*)addr =
-				(float) PyInt_AsLong(v);
-		else if (PyFloat_Check(v))
-			*(float*)addr =
-				(float) PyFloat_AsDouble(v);
-		else {
-			PyErr_BadArgument();
-			return -1;
 		}
+	case T_FLOAT:{
+		double double_val;
+		double_val = PyFloat_AsDouble(v);
+		if ((double_val == -1) && PyErr_Occurred())
+			return -1;
+		*(float*)addr = (float)double_val;
 		break;
+		}
 	case T_DOUBLE:
-		if (PyInt_Check(v))
-			*(double*)addr = (double) PyInt_AsLong(v);
-		else if (PyFloat_Check(v))
-			*(double*)addr = PyFloat_AsDouble(v);
-		else {
-			PyErr_BadArgument();
+		*(double*)addr = PyFloat_AsDouble(v);
+		if ((*(double*)addr == -1) && PyErr_Occurred())
 			return -1;
-		}
 		break;
 	case T_OBJECT:
 	case T_OBJECT_EX:


More information about the Python-checkins mailing list