Require GIL for pythonic division, check for division overflow
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 15 Apr 2009 07:27:57 +0000 (00:27 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 15 Apr 2009 07:27:57 +0000 (00:27 -0700)
Cython/Compiler/ExprNodes.py
tests/run/cdivision_CEP_516.pyx

index 9d274b94bab4c2fd71acbe7520a83da95be5df4d..732d5be891f6e28852a36d0804af400e8c89eb69 100644 (file)
@@ -4247,6 +4247,8 @@ class DivNode(NumBinopNode):
                 # Need to check ahead of time to warn or raise zero division error
                 self.operand1 = self.operand1.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):
         if self.type.is_int:
@@ -4272,6 +4274,15 @@ class DivNode(NumBinopNode):
                 code.putln('PyErr_Format(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
                 code.putln(code.error_goto(self.pos))
                 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']:
                 code.globalstate.use_utility_code(cdivision_warning_utility_code)
                 code.putln("if ((%s < 0) ^ (%s < 0)) {" % (
@@ -5772,3 +5783,10 @@ static int __Pyx_cdivision_warning(void) {
     'MODULENAME': Naming.modulename_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)))
+""")
index 82a55139af9e80470fe608719c7b49c862ede533..9866594e4c866eb37c08215d97bc2576c44e49fc 100644 (file)
@@ -64,6 +64,14 @@ verbose_call(5)
 'float division'
 >>> mod_div_zero_float(25, 0, 0)
 '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
@@ -147,3 +155,7 @@ def mod_div_zero_float(float a, float b, float c):
         return (a % b) / c
     except ZeroDivisionError, ex:
         return ex.message
+
+@cython.cdivision(False)
+def py_div_long(long a, long b):
+    return a / b