Patch #1549049: Rewrite type conversion in structmember.

Fixes #1545696 and #1566140. Will backport to 2.5.
This commit is contained in:
Martin v. Löwis 2006-10-27 06:16:31 +00:00
parent efb57072fe
commit b5bc537c5e
5 changed files with 299 additions and 64 deletions

View File

@ -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)

View File

@ -633,6 +633,7 @@ Stephen Turner
Bill Tutt Bill Tutt
Doobee R. Tzeck Doobee R. Tzeck
Lionel Ulmer Lionel Ulmer
Roger Upole
Michael Urman Michael Urman
Hector Urtubia Hector Urtubia
Dmitry Vasiliev Dmitry Vasiliev

View File

@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1?
Core and builtins 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) - Update the peephole optimizer to remove more dead code (jumps after returns)
and inline unconditional jumps to returns. and inline unconditional jumps to returns.

View File

@ -6,6 +6,8 @@
*/ */
#include "Python.h" #include "Python.h"
#include <values.h>
#include "structmember.h"
#ifdef WITH_THREAD #ifdef WITH_THREAD
#include "pythread.h" #include "pythread.h"
@ -35,13 +37,13 @@ raiseTestError(const char* test_name, const char* msg)
platforms have these hardcoded. Better safe than sorry. platforms have these hardcoded. Better safe than sorry.
*/ */
static PyObject* static PyObject*
sizeof_error(const char* fatname, const char* typename, sizeof_error(const char* fatname, const char* typname,
int expected, int got) int expected, int got)
{ {
char buf[1024]; char buf[1024];
PyOS_snprintf(buf, sizeof(buf), PyOS_snprintf(buf, sizeof(buf),
"%.200s #define == %d but sizeof(%.200s) == %d", "%.200s #define == %d but sizeof(%.200s) == %d",
fatname, expected, typename, got); fatname, expected, typname, got);
PyErr_SetString(TestError, buf); PyErr_SetString(TestError, buf);
return (PyObject*)NULL; return (PyObject*)NULL;
} }
@ -615,7 +617,7 @@ _make_call(void *callable)
{ {
PyObject *rc; PyObject *rc;
PyGILState_STATE s = PyGILState_Ensure(); PyGILState_STATE s = PyGILState_Ensure();
rc = PyObject_CallFunction(callable, ""); rc = PyObject_CallFunction((PyObject *)callable, "");
Py_XDECREF(rc); Py_XDECREF(rc);
PyGILState_Release(s); PyGILState_Release(s);
} }
@ -756,6 +758,105 @@ static PyMethodDef TestMethods[] = {
#define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);} #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 PyMODINIT_FUNC
init_testcapi(void) init_testcapi(void)
{ {
@ -765,16 +866,28 @@ init_testcapi(void)
if (m == NULL) if (m == NULL)
return; 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, "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, "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, "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_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_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); TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
Py_INCREF(TestError); Py_INCREF(TestError);

View File

@ -62,29 +62,28 @@ PyMember_GetOne(const char *addr, PyMemberDef *l)
addr += l->offset; addr += l->offset;
switch (l->type) { switch (l->type) {
case T_BYTE: case T_BYTE:
v = PyInt_FromLong( v = PyInt_FromLong(*(char*)addr);
(long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80));
break; break;
case T_UBYTE: case T_UBYTE:
v = PyInt_FromLong((long) *(char*)addr & 0xff); v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
break; break;
case T_SHORT: case T_SHORT:
v = PyInt_FromLong((long) *(short*)addr); v = PyInt_FromLong(*(short*)addr);
break; break;
case T_USHORT: case T_USHORT:
v = PyInt_FromLong((long) *(unsigned short*)addr); v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
break; break;
case T_INT: case T_INT:
v = PyInt_FromLong((long) *(int*)addr); v = PyInt_FromLong(*(int*)addr);
break; break;
case T_UINT: case T_UINT:
v = PyInt_FromLong((long) *(unsigned int*)addr); v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
break; break;
case T_LONG: case T_LONG:
v = PyInt_FromLong(*(long*)addr); v = PyInt_FromLong(*(long*)addr);
break; break;
case T_ULONG: case T_ULONG:
v = PyLong_FromDouble((double) *(unsigned long*)addr); v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
break; break;
case T_FLOAT: case T_FLOAT:
v = PyFloat_FromDouble((double)*(float*)addr); v = PyFloat_FromDouble((double)*(float*)addr);
@ -175,68 +174,107 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
} }
addr += l->offset; addr += l->offset;
switch (l->type) { switch (l->type) {
case T_BYTE: case T_BYTE:{
case T_UBYTE: long long_val;
if (!PyInt_Check(v)) { long_val = PyInt_AsLong(v);
PyErr_BadArgument(); if ((long_val == -1) && PyErr_Occurred())
return -1; return -1;
} /* XXX: For compatibility, only warn about truncations
*(char*)addr = (char) PyInt_AsLong(v); 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; break;
case T_SHORT:
case T_USHORT:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
} }
*(short*)addr = (short) PyInt_AsLong(v); case T_UBYTE:{
break; long long_val;
case T_UINT: long_val = PyInt_AsLong(v);
case T_INT: if ((long_val == -1) && PyErr_Occurred())
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1; return -1;
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;
} }
*(int*)addr = (int) PyInt_AsLong(v); case T_SHORT:{
break; long long_val;
case T_LONG: long_val = PyInt_AsLong(v);
if (!PyInt_Check(v)) { if ((long_val == -1) && PyErr_Occurred())
PyErr_BadArgument();
return -1; 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:{
break; long long_val;
case T_ULONG: long_val = PyInt_AsLong(v);
if (PyInt_Check(v)) if ((long_val == -1) && PyErr_Occurred())
*(long*)addr = PyInt_AsLong(v);
else if (PyLong_Check(v))
*(long*)addr = PyLong_AsLong(v);
else {
PyErr_BadArgument();
return -1; 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_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; 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; break;
}
case T_DOUBLE: case T_DOUBLE:
if (PyInt_Check(v)) *(double*)addr = PyFloat_AsDouble(v);
*(double*)addr = (double) PyInt_AsLong(v); if ((*(double*)addr == -1) && PyErr_Occurred())
else if (PyFloat_Check(v))
*(double*)addr = PyFloat_AsDouble(v);
else {
PyErr_BadArgument();
return -1; return -1;
}
break; break;
case T_OBJECT: case T_OBJECT:
case T_OBJECT_EX: case T_OBJECT_EX: