Commit 327e0209 authored by Robert Bradshaw's avatar Robert Bradshaw

Pyrex type conversion with overflow check for all int types.

parent 19ecd0df
...@@ -279,6 +279,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -279,6 +279,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_includes(env, cimported_modules, code) self.generate_includes(env, cimported_modules, code)
code.putln('') code.putln('')
code.put(Nodes.utility_function_predeclarations) code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations)
code.put(Nodes.branch_prediction_macros) code.put(Nodes.branch_prediction_macros)
code.putln('') code.putln('')
code.putln('static PyObject *%s;' % env.module_cname) code.putln('static PyObject *%s;' % env.module_cname)
...@@ -1598,6 +1599,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1598,6 +1599,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for utility_code in env.utility_code_used: for utility_code in env.utility_code_used:
code.h.put(utility_code[0]) code.h.put(utility_code[0])
code.put(utility_code[1]) code.put(utility_code[1])
code.put(PyrexTypes.type_conversion_functions)
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
...@@ -1745,11 +1747,11 @@ bad: ...@@ -1745,11 +1747,11 @@ bad:
register_cleanup_utility_code = [ register_cleanup_utility_code = [
""" """
static int __Pyx_RegisterCleanup(); /*proto*/ static int __Pyx_RegisterCleanup(void); /*proto*/
static PyObject* cleanup(PyObject *self, PyObject *unused); /*proto*/ static PyObject* cleanup(PyObject *self, PyObject *unused); /*proto*/
static PyMethodDef cleanup_def = {"__cleanup", (PyCFunction)&cleanup, METH_NOARGS, 0}; 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 /* Don't use Py_AtExit because that has a 32-call limit
* and is called after python finalization. * and is called after python finalization.
*/ */
......
...@@ -3068,22 +3068,6 @@ utility_function_predeclarations = \ ...@@ -3068,22 +3068,6 @@ utility_function_predeclarations = \
typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
typedef struct {PyObject **p; char *s; long n; int is_unicode;} __Pyx_StringTabEntry; /*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; static int %(skip_dispatch_cname)s = 0;
......
...@@ -359,19 +359,59 @@ class CNumericType(CType): ...@@ -359,19 +359,59 @@ class CNumericType(CType):
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl(self.sign_and_name(), dll_linkage) base = public_decl(self.sign_and_name(), dll_linkage)
return self.base_declaration_code(base, entity_code) return self.base_declaration_code(base, entity_code)
int_conversion_list = {}
type_conversion_functions = ""
type_conversion_predeclarations = ""
class CIntType(CNumericType): class CIntType(CNumericType):
is_int = 1 is_int = 1
typedef_flag = 0 typedef_flag = 0
to_py_function = "PyInt_FromLong" to_py_function = "PyInt_FromLong"
from_py_function = "PyInt_AsLong" from_py_function = "__pyx_PyInt_AsLong"
exception_value = -1 exception_value = -1
def __init__(self, rank, signed, pymemberdef_typecode = None, is_returncode = 0): def __init__(self, rank, signed, pymemberdef_typecode = None, is_returncode = 0):
CNumericType.__init__(self, rank, signed, pymemberdef_typecode) CNumericType.__init__(self, rank, signed, pymemberdef_typecode)
self.is_returncode = is_returncode 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): def assignable_from_resolved_type(self, src_type):
return src_type.is_int or src_type.is_enum or src_type is error_type return src_type.is_int or src_type.is_enum or src_type is error_type
...@@ -405,13 +445,13 @@ class CULongType(CUIntType): ...@@ -405,13 +445,13 @@ class CULongType(CUIntType):
class CLongLongType(CUIntType): class CLongLongType(CUIntType):
to_py_function = "PyLong_FromLongLong" to_py_function = "PyLong_FromLongLong"
from_py_function = "PyInt_AsUnsignedLongLongMask" from_py_function = "__pyx_PyInt_AsLongLong"
class CULongLongType(CUIntType): class CULongLongType(CUIntType):
to_py_function = "PyLong_FromUnsignedLongLong" to_py_function = "PyLong_FromUnsignedLongLong"
from_py_function = "PyInt_AsUnsignedLongLongMask" from_py_function = "__pyx_PyInt_AsUnsignedLongLong"
class CPySSizeTType(CIntType): class CPySSizeTType(CIntType):
...@@ -424,7 +464,7 @@ class CFloatType(CNumericType): ...@@ -424,7 +464,7 @@ class CFloatType(CNumericType):
is_float = 1 is_float = 1
to_py_function = "PyFloat_FromDouble" to_py_function = "PyFloat_FromDouble"
from_py_function = "PyFloat_AsDouble" from_py_function = "__pyx_PyFloat_AsDouble"
def __init__(self, rank, pymemberdef_typecode = None): def __init__(self, rank, pymemberdef_typecode = None):
CNumericType.__init__(self, rank, 1, pymemberdef_typecode) CNumericType.__init__(self, rank, 1, pymemberdef_typecode)
...@@ -828,6 +868,18 @@ class ErrorType(PyrexType): ...@@ -828,6 +868,18 @@ class ErrorType(PyrexType):
return 1 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() py_object_type = PyObjectType()
c_void_type = CVoidType() c_void_type = CVoidType()
...@@ -872,18 +924,6 @@ error_type = ErrorType() ...@@ -872,18 +924,6 @@ error_type = ErrorType()
lowest_float_rank = 6 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 = { sign_and_rank_to_type = {
#(signed, rank) #(signed, rank)
(0, 0, ): c_uchar_type, (0, 0, ): c_uchar_type,
...@@ -988,3 +1028,72 @@ def typecast(to_type, from_type, expr_code): ...@@ -988,3 +1028,72 @@ def typecast(to_type, from_type, expr_code):
else: else:
#print "typecast: to", to_type, "from", from_type ### #print "typecast: to", to_type, "from", from_type ###
return to_type.cast_code(expr_code) 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment