Commit 4d77dd8f authored by Robert Bradshaw's avatar Robert Bradshaw

control overflow with a directive

parent 5e89023e
...@@ -8008,10 +8008,9 @@ class NumBinopNode(BinopNode): ...@@ -8008,10 +8008,9 @@ class NumBinopNode(BinopNode):
return return
if self.type.is_complex: if self.type.is_complex:
self.infix = False self.infix = False
if self.type.is_int and self.operator in ('+', '-', '*', '/'): if self.type.is_int and env.directives['overflowcheck'] and self.operator in ('+', '-', '*'):
self.overflow_check = True self.overflow_check = True
binop = {'+': 'add', '-': 'sub', '*': 'mul', '/': 'div'}[self.operator] self.func = self.type.overflow_check_binop(self.op_names[self.operator], env)
self.func = self.type.overflow_check_binop(binop, env)
self.is_temp = True self.is_temp = True
if not self.infix or (type1.is_numeric and type2.is_numeric): if not self.infix or (type1.is_numeric and type2.is_numeric):
self.operand1 = self.operand1.coerce_to(self.type, env) self.operand1 = self.operand1.coerce_to(self.type, env)
...@@ -8112,6 +8111,12 @@ class NumBinopNode(BinopNode): ...@@ -8112,6 +8111,12 @@ class NumBinopNode(BinopNode):
"%": "PyNumber_Remainder", "%": "PyNumber_Remainder",
"**": "PyNumber_Power" "**": "PyNumber_Power"
} }
op_names = {
"+": "add",
"-": "sub",
"*": "mul",
}
class IntBinopNode(NumBinopNode): class IntBinopNode(NumBinopNode):
# Binary operation taking integer arguments. # Binary operation taking integer arguments.
......
...@@ -81,6 +81,7 @@ directive_defaults = { ...@@ -81,6 +81,7 @@ directive_defaults = {
'auto_cpdef': False, 'auto_cpdef': False,
'cdivision': False, # was True before 0.12 'cdivision': False, # was True before 0.12
'cdivision_warnings': False, 'cdivision_warnings': False,
'overflowcheck': False,
'always_allow_keywords': False, 'always_allow_keywords': False,
'allow_none_for_extension_args': True, 'allow_none_for_extension_args': True,
'wraparound' : True, 'wraparound' : True,
......
...@@ -80,17 +80,18 @@ static CYTHON_INLINE {{UINT}} __Pyx_mul_{{NAME}}_checking_overflow({{UINT}} a, { ...@@ -80,17 +80,18 @@ static CYTHON_INLINE {{UINT}} __Pyx_mul_{{NAME}}_checking_overflow({{UINT}} a, {
unsigned long big_r = ((unsigned long) a) * ((unsigned long) b); unsigned long big_r = ((unsigned long) a) * ((unsigned long) b);
{{UINT}} r = ({{UINT}}) big_r; {{UINT}} r = ({{UINT}}) big_r;
*overflow |= big_r != r; *overflow |= big_r != r;
return ({{UINT}}) r; return r;
} else if (sizeof({{UINT}}) < sizeof(long long)) { } else if (sizeof({{UINT}}) < sizeof(long long)) {
unsigned long long big_r = ((unsigned long long) a) * ((unsigned long long) b); unsigned long long big_r = ((unsigned long long) a) * ((unsigned long long) b);
{{UINT}} r = ({{UINT}}) big_r; {{UINT}} r = ({{UINT}}) big_r;
*overflow |= big_r != r; *overflow |= big_r != r;
return ({{UINT}}) r; return r;
} else { } else {
{{UINT}} prod = a * b; {{UINT}} prod = a * b;
double dprod = ((double) a) * ((double) b); double dprod = ((double) a) * ((double) b);
// False positives. Yes, the equality is required to avoid false negatives. // Overflow results in an error of at least 2^sizeof(UINT),
*overflow |= dprod >= (double) __PYX_MAX({{UINT}}); // whereas rounding represents an error on the order of 2^(sizeof(UINT)-53).
*overflow |= fabs(dprod - prod) > (__PYX_MAX({{UINT}}) / 2);
return prod; return prod;
} }
} }
...@@ -128,22 +129,22 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{INT}} ...@@ -128,22 +129,22 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{INT}}
/////////////// BaseCaseSigned /////////////// /////////////// BaseCaseSigned ///////////////
#define TOP_TWO_BITS(value, type) (value & ((unsigned type)3 << (sizeof(type) * 8 - 2)))
static CYTHON_INLINE {{INT}} __Pyx_add_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { static CYTHON_INLINE {{INT}} __Pyx_add_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) {
if (sizeof({{INT}}) < sizeof(long)) { if (sizeof({{INT}}) < sizeof(long)) {
long big_r = ((long) a) + ((long) b); long big_r = ((long) a) + ((long) b);
{{INT}} r = ({{INT}}) big_r; {{INT}} r = ({{INT}}) big_r;
*overflow |= big_r != r; *overflow |= big_r != r;
return ({{INT}}) r; return r;
} else if (sizeof({{INT}}) < sizeof(long long)) { } else if (sizeof({{INT}}) < sizeof(long long)) {
long long big_r = ((long long) a) + ((long long) b); long long big_r = ((long long) a) + ((long long) b);
{{INT}} r = ({{INT}}) big_r; {{INT}} r = ({{INT}}) big_r;
*overflow |= big_r != r; *overflow |= big_r != r;
return ({{INT}}) r; return r;
} else { } else {
// Signed overflow undefined, but unsigned is well defined. // Signed overflow undefined, but unsigned overflow is well defined.
{{INT}} r = ({{INT}}) ((unsigned {{INT}}) a + (unsigned {{INT}}) b); {{INT}} r = ({{INT}}) ((unsigned {{INT}}) a + (unsigned {{INT}}) b);
// Overflow happened if the operands have the same sign, but the result
// has opposite sign.
// sign(a) == sign(b) != sign(r) // sign(a) == sign(b) != sign(r)
{{INT}} sign_a = __PYX_SIGN_BIT({{INT}}) & a; {{INT}} sign_a = __PYX_SIGN_BIT({{INT}}) & a;
{{INT}} sign_b = __PYX_SIGN_BIT({{INT}}) & b; {{INT}} sign_b = __PYX_SIGN_BIT({{INT}}) & b;
...@@ -186,8 +187,9 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_{{NAME}}_checking_overflow({{INT}} a, {{I ...@@ -186,8 +187,9 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_{{NAME}}_checking_overflow({{INT}} a, {{I
} else { } else {
{{INT}} prod = a * b; {{INT}} prod = a * b;
double dprod = ((double) a) * ((double) b); double dprod = ((double) a) * ((double) b);
// False positives. // Overflow results in an error of at least 2^sizeof(INT),
*overflow |= fabs(dprod) > (double) __PYX_MAX({{INT}}); // whereas rounding represents an error on the order of 2^(sizeof(INT)-53).
*overflow |= fabs(dprod - prod) > (__PYX_MAX({{INT}}) / 2);
return prod; return prod;
} }
} }
......
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