Commit 13617b61 authored by Stefan Behnel's avatar Stefan Behnel

Merge branch '0.29.x'

parents b8e2e12e 272efcf6
......@@ -92,6 +92,13 @@ Other changes
* Support for Python 2.6 was removed.
0.29.4 (2019-02-01)
===================
* Division of numeric constants by a runtime value of 0 could fail to raise a
``ZeroDivisionError``. (Github issue #2820)
0.29.3 (2019-01-19)
===================
......
......@@ -3166,6 +3166,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
PyrexTypes.CFuncTypeArg("op2", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("cval", ctype, None),
PyrexTypes.CFuncTypeArg("inplace", PyrexTypes.c_bint_type, None),
PyrexTypes.CFuncTypeArg("zerodiv_check", PyrexTypes.c_bint_type, None),
], exception_value=None if ret_type.is_pyobject else ret_type.exception_value))
for ctype in (PyrexTypes.c_long_type, PyrexTypes.c_double_type)
for ret_type in (PyrexTypes.py_object_type, PyrexTypes.c_bint_type)
......@@ -3300,12 +3301,22 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
# Cut off at an integer border that is still safe for all operations.
return node
if operator in ('TrueDivide', 'FloorDivide', 'Divide', 'Remainder'):
if args[1].constant_result == 0:
# Don't optimise division by 0. :)
return node
args = list(args)
args.append((ExprNodes.FloatNode if is_float else ExprNodes.IntNode)(
numval.pos, value=numval.value, constant_result=numval.constant_result,
type=num_type))
inplace = node.inplace if isinstance(node, ExprNodes.NumBinopNode) else False
args.append(ExprNodes.BoolNode(node.pos, value=inplace, constant_result=inplace))
if is_float or operator not in ('Eq', 'Ne'):
# "PyFloatBinop" and "PyIntBinop" take an additional "check for zero division" argument.
zerodivision_check = arg_order == 'CObj' and (
not node.cdivision if isinstance(node, ExprNodes.DivNode) else False)
args.append(ExprNodes.BoolNode(node.pos, value=zerodivision_check, constant_result=zerodivision_check))
utility_code = TempitaUtilityCode.load_cached(
"PyFloatBinop" if is_float else "PyIntCompare" if operator in ('Eq', 'Ne') else "PyIntBinop",
......
This diff is collapsed.
......@@ -26,6 +26,39 @@ def float_by_float():
return 3.0 / 2.0
def div_by_0(x):
"""
>>> div_by_0(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(1) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(1.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> float('inf') / 0.0 # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(float('inf')) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(float('-inf')) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> float('nan') / 0.0 # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_by_0(float('nan')) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return x / 0.0
def div_1_by(x):
"""
>>> div_1_by(1.0)
......@@ -42,6 +75,12 @@ def div_1_by(x):
-0.0
>>> div_1_by(float('nan'))
nan
>>> div_1_by(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_1_by(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return 1.0 / x
......@@ -116,6 +155,12 @@ def div_neg_2_by(x):
nan
>>> div_neg_2_by(float('nan'))
nan
>>> div_neg_2_by(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_neg_2_by(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return (-2.0) / x
......@@ -148,6 +193,12 @@ def div_nan_by(x):
nan
>>> div_nan_by(float('nan'))
nan
>>> div_nan_by(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_nan_by(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return float("nan") / x
......@@ -182,6 +233,15 @@ def div_inf_by(x):
nan
>>> div_inf_by(float('-inf'))
nan
>>> float("inf") / 0.0 # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_inf_by(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_inf_by(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return float("inf") / x
......@@ -196,5 +256,14 @@ def div_neg_inf_by(x):
inf
>>> div_neg_inf_by(-1.0)
inf
>>> float("-inf") / 0.0 # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_neg_inf_by(0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
>>> div_neg_inf_by(0.0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: float division...
"""
return float("-inf") / x
......@@ -157,3 +157,73 @@ def int_int(int a, int b):
(0.5, 2.0)
"""
return a/b, b/a
def div_by_0(a):
"""
>>> div_by_0(0)
'OK'
>>> div_by_0(0.0)
'OK'
"""
try:
1/a
except ZeroDivisionError:
pass
else:
return "FAIL 1"
try:
1//a
except ZeroDivisionError:
pass
else:
return "FAIL 2"
try:
5.0/a
except ZeroDivisionError:
pass
else:
return "FAIL 3"
try:
5.0//a
except ZeroDivisionError:
pass
else:
return "FAIL 4"
try:
5/a
except ZeroDivisionError:
pass
else:
return "FAIL 5"
try:
5//a
except ZeroDivisionError:
pass
else:
return "FAIL 6"
try:
(2**15)/a
except ZeroDivisionError:
pass
else:
return "FAIL 7"
try:
(2**15)//a
except ZeroDivisionError:
pass
else:
return "FAIL 8"
try:
(2**30)/a
except ZeroDivisionError:
pass
else:
return "FAIL 9"
try:
(2**30)//a
except ZeroDivisionError:
pass
else:
return "FAIL 10"
return 'OK'
......@@ -7,6 +7,9 @@ def modobj(obj2, obj3):
1
>>> modobj('%d', 5)
'5'
>>> modobj(1, 0) # doctest: +ELLIPSIS
Traceback (most recent call last):
ZeroDivisionError: integer division or modulo by zero
"""
obj1 = obj2 % obj3
return obj1
......
......@@ -143,3 +143,73 @@ def int_int(int a, int b):
(0, 2)
"""
return a/b, b/a
def div_by_0(a):
"""
>>> div_by_0(0)
'OK'
>>> div_by_0(0.0)
'OK'
"""
try:
1/a
except ZeroDivisionError:
pass
else:
return "FAIL 1"
try:
1//a
except ZeroDivisionError:
pass
else:
return "FAIL 2"
try:
5.0/a
except ZeroDivisionError:
pass
else:
return "FAIL 3"
try:
5.0//a
except ZeroDivisionError:
pass
else:
return "FAIL 4"
try:
5/a
except ZeroDivisionError:
pass
else:
return "FAIL 5"
try:
5//a
except ZeroDivisionError:
pass
else:
return "FAIL 6"
try:
(2**15)/a
except ZeroDivisionError:
pass
else:
return "FAIL 7"
try:
(2**15)//a
except ZeroDivisionError:
pass
else:
return "FAIL 8"
try:
(2**30)/a
except ZeroDivisionError:
pass
else:
return "FAIL 9"
try:
(2**30)//a
except ZeroDivisionError:
pass
else:
return "FAIL 10"
return 'OK'
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