From: Robert Bradshaw Date: Wed, 5 Dec 2007 22:38:25 +0000 (-0800) Subject: Pyrex type conversion with overflow check for all int types. X-Git-Tag: 0.9.6.14~29^2~89 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=327e0209f2afa5af0a945b0b083ec4ad6eb461d8;p=cython.git Pyrex type conversion with overflow check for all int types. --- diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 3fe07989..05befd1b 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -279,6 +279,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_includes(env, cimported_modules, code) code.putln('') code.put(Nodes.utility_function_predeclarations) + code.put(PyrexTypes.type_conversion_predeclarations) code.put(Nodes.branch_prediction_macros) code.putln('') code.putln('static PyObject *%s;' % env.module_cname) @@ -1598,6 +1599,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): for utility_code in env.utility_code_used: code.h.put(utility_code[0]) code.put(utility_code[1]) + code.put(PyrexTypes.type_conversion_functions) #------------------------------------------------------------------------------------ # @@ -1745,11 +1747,11 @@ bad: register_cleanup_utility_code = [ """ -static int __Pyx_RegisterCleanup(); /*proto*/ +static int __Pyx_RegisterCleanup(void); /*proto*/ static PyObject* cleanup(PyObject *self, PyObject *unused); /*proto*/ static PyMethodDef cleanup_def = {"__cleanup", (PyCFunction)&cleanup, METH_NOARGS, 0}; """,""" -static int __Pyx_RegisterCleanup() { +static int __Pyx_RegisterCleanup(void) { /* Don't use Py_AtExit because that has a 32-call limit * and is called after python finalization. */ diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 2cf5c38f..95f65222 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -3068,22 +3068,6 @@ utility_function_predeclarations = \ typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ typedef struct {PyObject **p; char *s; long n; int is_unicode;} __Pyx_StringTabEntry; /*proto*/ -static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject* x = PyNumber_Index(b); - if (!x) return -1; - ival = PyInt_AsSsize_t(x); - Py_DECREF(x); - return ival; -} - -#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) -static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - if (x == Py_True) return 1; - else if (x == Py_False) return 0; - else return PyObject_IsTrue(x); -} - """ + """ static int %(skip_dispatch_cname)s = 0; diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 2f8baf2b..f37028db 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -359,19 +359,59 @@ class CNumericType(CType): for_display = 0, dll_linkage = None, pyrex = 0): base = public_decl(self.sign_and_name(), dll_linkage) return self.base_declaration_code(base, entity_code) - + + +int_conversion_list = {} +type_conversion_functions = "" +type_conversion_predeclarations = "" class CIntType(CNumericType): is_int = 1 typedef_flag = 0 to_py_function = "PyInt_FromLong" - from_py_function = "PyInt_AsLong" + from_py_function = "__pyx_PyInt_AsLong" exception_value = -1 def __init__(self, rank, signed, pymemberdef_typecode = None, is_returncode = 0): CNumericType.__init__(self, rank, signed, pymemberdef_typecode) self.is_returncode = is_returncode + if self.from_py_function == '__pyx_PyInt_AsLong': + self.from_py_function = self.get_type_conversion() + + def get_type_conversion(self): + # error on overflow + c_type = self.sign_and_name() + c_name = c_type.replace(' ', '_'); + func_name = "__pyx_PyInt_%s" % c_name; + c_mask = "__pyx_%s_MASK" % c_name + if not int_conversion_list.has_key(func_name): + # no env to add utility code to + global type_conversion_predeclarations, type_conversion_functions + if self.signed: + neg_test = " && ((-val) & %s)" % c_mask + else: + neg_test = "" + type_conversion_predeclarations += """ +static INLINE %(c_type)s %(func_name)s(PyObject* x);""" % {'c_type': c_type, 'c_name': c_name, 'func_name': func_name } + type_conversion_functions += """ +#define %(c_mask)s ((long)(~((1LL << (8*sizeof(%(c_type)s))) - 1LL))) +static INLINE %(c_type)s %(func_name)s(PyObject* x) { + if (sizeof(%(c_type)s) < sizeof(long)) { + long val = __pyx_PyInt_AsLong(x); + if (unlikely((val & %(c_mask)s) %(neg_test)s)) { + PyErr_SetString(PyExc_OverflowError, "value too large to convert to %(c_type)s"); + return (%(c_type)s)-1; + } + return (%(c_type)s)val; + } + else { + return __pyx_PyInt_AsLong(x); + } +} +""" % {'c_type': c_type, 'c_name': c_name, 'func_name': func_name, 'c_mask': c_mask, 'neg_test': neg_test } + int_conversion_list[func_name] = True + return func_name def assignable_from_resolved_type(self, src_type): return src_type.is_int or src_type.is_enum or src_type is error_type @@ -405,13 +445,13 @@ class CULongType(CUIntType): class CLongLongType(CUIntType): to_py_function = "PyLong_FromLongLong" - from_py_function = "PyInt_AsUnsignedLongLongMask" + from_py_function = "__pyx_PyInt_AsLongLong" class CULongLongType(CUIntType): to_py_function = "PyLong_FromUnsignedLongLong" - from_py_function = "PyInt_AsUnsignedLongLongMask" + from_py_function = "__pyx_PyInt_AsUnsignedLongLong" class CPySSizeTType(CIntType): @@ -424,7 +464,7 @@ class CFloatType(CNumericType): is_float = 1 to_py_function = "PyFloat_FromDouble" - from_py_function = "PyFloat_AsDouble" + from_py_function = "__pyx_PyFloat_AsDouble" def __init__(self, rank, pymemberdef_typecode = None): CNumericType.__init__(self, rank, 1, pymemberdef_typecode) @@ -828,6 +868,18 @@ class ErrorType(PyrexType): return 1 +rank_to_type_name = ( + "char", # 0 + "short", # 1 + "int", # 2 + "long", # 3 + "PY_LONG_LONG", # 4 + "Py_ssize_t", # 5 + "float", # 6 + "double", # 7 + "long double", # 8 +) + py_object_type = PyObjectType() c_void_type = CVoidType() @@ -872,18 +924,6 @@ error_type = ErrorType() lowest_float_rank = 6 -rank_to_type_name = ( - "char", # 0 - "short", # 1 - "int", # 2 - "long", # 3 - "PY_LONG_LONG", # 4 - "Py_ssize_t", # 5 - "float", # 6 - "double", # 7 - "long double", # 8 -) - sign_and_rank_to_type = { #(signed, rank) (0, 0, ): c_uchar_type, @@ -988,3 +1028,72 @@ def typecast(to_type, from_type, expr_code): else: #print "typecast: to", to_type, "from", from_type ### return to_type.cast_code(expr_code) + + +type_conversion_predeclarations = """ +/* Type Conversion Predeclarations */ + +#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) +static INLINE int __Pyx_PyObject_IsTrue(PyObject* x); +static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x); +static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x); +static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b); + +#define __pyx_PyInt_AsLong(x) (PyInt_CheckExact(x) ? PyInt_AS_LONG(x) : PyInt_AsLong(x)) +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +""" + type_conversion_predeclarations + +type_conversion_functions = """ +/* Type Conversion Functions */ + +static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject* x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} + +static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + if (x == Py_True) return 1; + else if (x == Py_False) return 0; + else return PyObject_IsTrue(x); +} + +static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) { + if (PyInt_CheckExact(x)) { + return PyInt_AS_LONG(x); + } + else if (PyLong_CheckExact(x)) { + return PyLong_AsLongLong(x); + } + else { + PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1; + PY_LONG_LONG val = __pyx_PyInt_AsLongLong(tmp); + Py_DECREF(tmp); + return val; + } +} + +static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x) { + if (PyInt_CheckExact(x)) { + long val = PyInt_AS_LONG(x); + if (unlikely(val < 0)) { + PyErr_SetString(PyExc_TypeError, "Negative assignment to unsigned type."); + return (unsigned PY_LONG_LONG)-1; + } + return val; + } + else if (PyLong_CheckExact(x)) { + return PyLong_AsUnsignedLongLong(x); + } + else { + PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1; + PY_LONG_LONG val = __pyx_PyInt_AsUnsignedLongLong(tmp); + Py_DECREF(tmp); + return val; + } +} + +""" + type_conversion_functions