add visible warning when negative indices are used in wraparound=False sections
authorStefan Behnel <stefan_ml@behnel.de>
Thu, 25 Apr 2013 13:47:26 +0000 (15:47 +0200)
committerStefan Behnel <stefan_ml@behnel.de>
Thu, 25 Apr 2013 13:47:26 +0000 (15:47 +0200)
Cython/Compiler/ExprNodes.py
tests/errors/wraparound_warnings.pyx [new file with mode: 0644]

index 2ef2ce6..d8f153b 100755 (executable)
@@ -91,6 +91,7 @@ def find_coercion_error(type_tuple, default, env):
     else:
         return err
 
+
 def default_str_type(env):
     return {
         'bytes': bytes_type,
@@ -99,6 +100,22 @@ def default_str_type(env):
     }.get(env.directives['c_string_type'])
 
 
+def check_negative_indices(*nodes):
+    """
+    Raise a warning on nodes that are known to have negative numeric values.
+    Used to find (potential) bugs inside of "wraparound=False" sections.
+    """
+    for node in nodes:
+        if not isinstance(node.constant_result, (int, float, long)):
+            continue
+        if node.constant_result >= 0:
+            continue
+        warning(node.pos,
+                "the result of using negative indices inside of "
+                "code sections marked as 'wraparound=False' is "
+                "undefined", level=1)
+
+
 class ExprNode(Node):
     #  subexprs     [string]     Class var holding names of subexpr node attrs
     #  type         PyrexType    Type of the result
@@ -2762,6 +2779,12 @@ class IndexNode(ExprNode):
 
         is_slice = isinstance(self.index, SliceNode)
 
+        if not env.directives['wraparound']:
+            if is_slice:
+                check_negative_indices(self.index.start, self.index.stop)
+            else:
+                check_negative_indices(self.index)
+
         # Potentially overflowing index value.
         if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value):
             self.index = self.index.coerce_to_pyobject(env)
@@ -3550,6 +3573,10 @@ class SliceIndexNode(ExprNode):
             self.start = self.start.analyse_types(env)
         if self.stop:
             self.stop = self.stop.analyse_types(env)
+
+        if not env.directives['wraparound']:
+            check_negative_indices(self.start, self.stop)
+
         base_type = self.base.type
         if base_type.is_string or base_type.is_cpp_string:
             self.type = default_str_type(env)
diff --git a/tests/errors/wraparound_warnings.pyx b/tests/errors/wraparound_warnings.pyx
new file mode 100644 (file)
index 0000000..5d88bed
--- /dev/null
@@ -0,0 +1,47 @@
+# mode: error
+# tag: werror
+
+cimport cython
+
+s = "abc"
+l = [1, 2, 3]
+
+def normal_wraparound(int i, bytes B not None, list L not None):
+    a = s[1:2]
+    a = s[-2:-1]
+    a = "abc"[-2:-1]
+    a = "abc"[-2:i]
+    a = B[-2:-1]
+
+    b = l[1:2]
+    b = l[-2:-1]
+    b = [1, 2, 3][-2:-1]
+    b = [1, 2, 3][-2:i]
+    b = L[-2:-1]
+
+@cython.wraparound(False)
+def no_wraparound(int i, bytes B not None, list L not None):
+    a = s[1:2]
+    a = s[-2:-1]
+    a = "abc"[-2:-1]
+    a = "abc"[-2:i]
+    a = B[-2:-1]
+
+    b = l[1:2]
+    b = l[-2:-1]
+    b = [1, 2, 3][-2:i]
+    b = L[-2:-1]
+
+
+_ERRORS = """
+25:11: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+25:14: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+27:15: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+28:11: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+28:14: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+31:11: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+31:14: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+32:19: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+33:11: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+33:14: the result of using negative indices inside of code sections marked as 'wraparound=False' is undefined
+"""