Commit 5e89023e authored by Robert Bradshaw's avatar Robert Bradshaw

First pass at int overflow checking.

parent 498b9db0
......@@ -7997,6 +7997,7 @@ class NumBinopNode(BinopNode):
# Binary operation taking numeric arguments.
infix = True
overflow_check = False
def analyse_c_operation(self, env):
type1 = self.operand1.type
......@@ -8007,6 +8008,11 @@ class NumBinopNode(BinopNode):
return
if self.type.is_complex:
self.infix = False
if self.type.is_int and self.operator in ('+', '-', '*', '/'):
self.overflow_check = True
binop = {'+': 'add', '-': 'sub', '*': 'mul', '/': 'div'}[self.operator]
self.func = self.type.overflow_check_binop(binop, env)
self.is_temp = True
if not self.infix or (type1.is_numeric and type2.is_numeric):
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
......@@ -8048,8 +8054,26 @@ class NumBinopNode(BinopNode):
return (type1.is_numeric or type1.is_enum) \
and (type2.is_numeric or type2.is_enum)
def generate_result_code(self, code):
super(NumBinopNode, self).generate_result_code(code)
if self.overflow_check:
self.overflow_bit = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = 0;" % self.overflow_bit);
code.putln("%s = %s;" % (self.result(), self.calculate_result_code()))
code.putln("if (unlikely(%s)) {" % self.overflow_bit)
code.putln('PyErr_Format(PyExc_OverflowError, "value too large");')
code.putln(code.error_goto(self.pos))
code.putln("}")
code.funcstate.release_temp(self.overflow_bit)
def calculate_result_code(self):
if self.infix:
if self.overflow_check:
return "%s(%s, %s, &%s)" % (
self.func,
self.operand1.result(),
self.operand2.result(),
self.overflow_bit)
elif self.infix:
return "(%s %s %s)" % (
self.operand1.result(),
self.operator,
......
......@@ -25,7 +25,7 @@ class BaseType(object):
# This is not entirely robust.
safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789'
all = []
for c in self.declaration_code("").replace(" ", "__"):
for c in self.declaration_code("").replace("unsigned ", "unsigned_").replace("long long", "long_long").replace(" ", "__"):
if c in safe:
all.append(c)
else:
......@@ -1548,6 +1548,30 @@ class CIntType(CNumericType):
# be negative for signed ints, which is good.
return "0xbad0bad0";
def overflow_check_binop(self, binop, env):
env.use_utility_code(UtilityCode.load("Common", "Overflow.c"))
type = self.declaration_code("")
name = self.specialization_name()
if type in ('int', 'long', 'long long'):
env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name}))
elif type in ('unsigned int', 'unsigned long', 'unsigned long long'):
env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name}))
elif self.rank <= 1:
# sizeof(short) < sizeof(int)
return "__Pyx_%s_%s_no_overflow" % (binop, name)
else:
_load_overflow_base(env)
env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop}))
return "__Pyx_%s_%s_checking_overflow" % (binop, name)
def _load_overflow_base(env):
env.use_utility_code(UtilityCode.load("Common", "Overflow.c"))
for type in ('int', 'long', 'long long'):
env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': type.replace(' ', '_')}))
for type in ('unsigned int', 'unsigned long', 'unsigned long long'):
env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': type.replace(' ', '_')}))
class CAnonEnumType(CIntType):
is_enum = 1
......
This diff is collapsed.
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