From: Stefan Behnel Date: Fri, 14 Nov 2008 18:20:43 +0000 (+0100) Subject: compile time/runtime checks for array slice assignments X-Git-Tag: 0.11-beta~254 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=38cf8831515385106d34c09a5caeba5061d07105;p=cython.git compile time/runtime checks for array slice assignments --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 74276592..3d15ca90 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -1830,6 +1830,7 @@ class SliceIndexNode(ExprNode): if rhs.type.is_array: # FIXME: we should check both array sizes here array_length = rhs.type.size + self.generate_slice_guard_code(code, array_length) else: # FIXME: fix the array size according to start/stop array_length = self.base.type.size @@ -1852,6 +1853,54 @@ class SliceIndexNode(ExprNode): self.start_code(), self.stop_code())) self.generate_subexpr_disposal_code(code) + + def generate_slice_guard_code(self, code, target_size): + if not self.base.type.is_array: + return + slice_size = self.base.type.size + start = stop = None + if self.stop: + stop = self.stop.result() + try: + stop = int(stop) + if stop > 0: + slice_size = stop + else: + slice_size = self.base.type.size + stop + stop = None + except ValueError: + pass + if self.start: + start = self.start.result() + try: + start = int(start) + if start < 0: + start = self.base.type.size + start + slice_size -= start + start = None + except ValueError: + pass + check = None + if slice_size < 0: + if target_size > 0: + error(self.pos, "Assignment to empty slice.") + elif start is None and stop is None: + # we know the exact slice length + if target_size != slice_size: + error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % ( + slice_size, target_size)) + elif start is not None: + if stop is None: + stop = slice_size + check = "(%s)-(%s)" % (stop, start) + else: # stop is not None: + check = stop + if check: + code.putln("if (unlikely((%s) != %d)) {" % (check, target_size)) + code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%d, got %%d", %d, (%s));' % ( + target_size, check)) + code.putln(code.error_goto(self.pos)) + code.putln("}") def start_code(self): if self.start: diff --git a/tests/run/arrayassign.pyx b/tests/run/arrayassign.pyx index b9018a42..e0734979 100644 --- a/tests/run/arrayassign.pyx +++ b/tests/run/arrayassign.pyx @@ -8,12 +8,44 @@ __doc__ = u""" >>> test_literal_list_slice_start_end() (1, 2, 3, 4, 5) ->>> test_literal_list_slice_start_param(2) +>>> test_literal_list_slice_start_param(4) (1, 2, 3, 4, 5) ->>> test_literal_list_slice_end_param(4) +>>> test_literal_list_slice_start_param(3) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 6 +>>> test_literal_list_slice_start_param(5) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 4 + +>>> test_literal_list_slice_end_param(5) (1, 2, 3, 4, 5) +>>> test_literal_list_slice_end_param(4) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 4 +>>> test_literal_list_slice_end_param(6) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 6 + >>> test_literal_list_slice_start_end_param(2,7) (1, 2, 3, 4, 5) +>>> test_literal_list_slice_start_end_param(3,7) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 4 +>>> test_literal_list_slice_start_end_param(1,7) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 6 +>>> test_literal_list_slice_start_end_param(2,6) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 4 +>>> test_literal_list_slice_start_end_param(2,8) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 6 +>>> test_literal_list_slice_start_end_param(3,6) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 3 +>>> test_literal_list_slice_start_end_param(1,8) +Traceback (most recent call last): +ValueError: Assignment to slice of wrong length, expected 5, got 7 >>> test_ptr_literal_list_slice_all() (1, 2, 3, 4, 5) @@ -53,7 +85,7 @@ def test_literal_list_slice_start_end(): def test_literal_list_slice_start_param(s): cdef int a[9] # = [9,8,7,6,5,4,3,2,1] a[s:] = [1,2,3,4,5] - return (a[2], a[3], a[4], a[5], a[6]) + return (a[4], a[5], a[6], a[7], a[8]) # return a[s:] def test_literal_list_slice_end_param(e):