Commit 1d47a9ef authored by Robert Bradshaw's avatar Robert Bradshaw

Require GIL for pythonic division, check for division overflow

parent bf6d9824
...@@ -4247,6 +4247,8 @@ class DivNode(NumBinopNode): ...@@ -4247,6 +4247,8 @@ class DivNode(NumBinopNode):
# Need to check ahead of time to warn or raise zero division error # Need to check ahead of time to warn or raise zero division error
self.operand1 = self.operand1.coerce_to_simple(env) self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env) self.operand2 = self.operand2.coerce_to_simple(env)
if env.nogil:
error(self.pos, "Pythonic division not allowed without gil, consider using cython.cdivision(True)")
def zero_division_message(self): def zero_division_message(self):
if self.type.is_int: if self.type.is_int:
...@@ -4272,6 +4274,15 @@ class DivNode(NumBinopNode): ...@@ -4272,6 +4274,15 @@ class DivNode(NumBinopNode):
code.putln('PyErr_Format(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message()) code.putln('PyErr_Format(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
code.putln("}") code.putln("}")
if self.type.is_int and self.type.signed and self.operator != '%':
code.globalstate.use_utility_code(division_overflow_test_code)
code.putln("else if (sizeof(%s) == sizeof(long) && unlikely(%s == -1) && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % (
self.type.declaration_code(''),
self.operand2.result(),
self.operand1.result()))
code.putln('PyErr_Format(PyExc_OverflowError, "value too large to perform division");')
code.putln(code.error_goto(self.pos))
code.putln("}")
if code.globalstate.directives['cdivision_warnings']: if code.globalstate.directives['cdivision_warnings']:
code.globalstate.use_utility_code(cdivision_warning_utility_code) code.globalstate.use_utility_code(cdivision_warning_utility_code)
code.putln("if ((%s < 0) ^ (%s < 0)) {" % ( code.putln("if ((%s < 0) ^ (%s < 0)) {" % (
...@@ -5772,3 +5783,10 @@ static int __Pyx_cdivision_warning(void) { ...@@ -5772,3 +5783,10 @@ static int __Pyx_cdivision_warning(void) {
'MODULENAME': Naming.modulename_cname, 'MODULENAME': Naming.modulename_cname,
'LINENO': Naming.lineno_cname, 'LINENO': Naming.lineno_cname,
}) })
# from intobject.c
division_overflow_test_code = UtilityCode(
proto="""
#define UNARY_NEG_WOULD_OVERFLOW(x) \
(((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
""")
...@@ -64,6 +64,14 @@ verbose_call(5) ...@@ -64,6 +64,14 @@ verbose_call(5)
'float division' 'float division'
>>> mod_div_zero_float(25, 0, 0) >>> mod_div_zero_float(25, 0, 0)
'float divmod()' 'float divmod()'
>>> import sys
>>> py_div_long(-5, -1)
5
>>> py_div_long(-sys.maxint-1, -1)
Traceback (most recent call last):
...
OverflowError: value too large to perform division
""" """
cimport cython cimport cython
...@@ -147,3 +155,7 @@ def mod_div_zero_float(float a, float b, float c): ...@@ -147,3 +155,7 @@ def mod_div_zero_float(float a, float b, float c):
return (a % b) / c return (a % b) / c
except ZeroDivisionError, ex: except ZeroDivisionError, ex:
return ex.message return ex.message
@cython.cdivision(False)
def py_div_long(long a, long b):
return a / b
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