Track max accessed array element, reject additional out-of-bounds accesses
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 2 Apr 2010 01:31:11 +0000 (18:31 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 2 Apr 2010 01:35:08 +0000 (18:35 -0700)
For unsized arrays, we can't flag out-of-bounds accesses until the
array is redeclared with a size.  Track the maximum accessed element
and generate an error if the declaration specifies a size that would
cause that access to be out-of-bounds.

This causes the following tests to pass:

    glslparsertest/shaders/array10.frag

ast_to_hir.cpp
ir.cpp
ir.h

index ff9cbb0..ca3c869 100644 (file)
@@ -898,13 +898,29 @@ ast_expression::hir(exec_list *instructions,
 
       error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
 
-      result = new ir_dereference(op[0], op[1]);
+      ir_dereference *const lhs = op[0]->as_dereference();
+      ir_instruction *array;
+      if ((lhs != NULL)
+         && (lhs->mode == ir_dereference::ir_reference_variable)) {
+        result = new ir_dereference(lhs->var, op[1]);
+
+        delete op[0];
+        array = lhs->var;
+      } else {
+        result = new ir_dereference(op[0], op[1]);
+        array = op[0];
+      }
+
+      /* Do not use op[0] after this point.  Use array.
+       */
+      op[0] = NULL;
+
 
       if (error_emitted)
         break;
 
       /* FINISHME: Handle vectors and matrices accessed with []. */
-      if (!op[0]->type->is_array()) {
+      if (!array->type->is_array()) {
         _mesa_glsl_error(& index_loc, state,
                          "cannot dereference non-array");
         error_emitted = true;
@@ -937,11 +953,11 @@ ast_expression::hir(exec_list *instructions,
          *    declared size. It is also illegal to index an array with a
          *    negative constant expression."
          */
-        if ((op[0]->type->array_size() > 0)
-            && (op[0]->type->array_size() <= idx)) {
+        if ((array->type->array_size() > 0)
+            && (array->type->array_size() <= idx)) {
            _mesa_glsl_error(& loc, state,
                             "array index must be < %u",
-                            op[0]->type->array_size());
+                            array->type->array_size());
            error_emitted = true;
         }
 
@@ -950,6 +966,10 @@ ast_expression::hir(exec_list *instructions,
                             "array index must be >= 0");
            error_emitted = true;
         }
+
+        ir_variable *const v = array->as_variable();
+        if ((v != NULL) && (unsigned(idx) > v->max_array_access))
+           v->max_array_access = idx;
       }
 
       if (error_emitted)
@@ -1265,9 +1285,15 @@ ast_declarator_list::hir(exec_list *instructions,
             * FINISHME: declarations.  It's not 100% clear whether this is
             * FINISHME: required or not.
             */
-           /* FINISHME: Check that the array hasn't already been accessed
-            * FINISHME: beyond the newly defined bounds.
-            */
+
+           if (var->type->array_size() <= earlier->max_array_access) {
+              YYLTYPE loc = this->get_location();
+
+              _mesa_glsl_error(& loc, state, "array size must be > %u due to "
+                               "previous access",
+                               earlier->max_array_access);
+           }
+
            earlier->type = var->type;
            delete var;
            var = NULL;
diff --git a/ir.cpp b/ir.cpp
index 60f34ca..3939e5a 100644 (file)
--- a/ir.cpp
+++ b/ir.cpp
@@ -246,7 +246,7 @@ ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
 
 
 ir_variable::ir_variable(const struct glsl_type *type, const char *name)
-   : ir_instruction(), read_only(false), centroid(false), invariant(false),
+   : max_array_access(0), read_only(false), centroid(false), invariant(false),
      mode(ir_var_auto), interpolation(ir_var_smooth)
 {
    this->type = type;
diff --git a/ir.h b/ir.h
index de6f093..8892f1d 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -121,6 +121,7 @@ public:
    {
       ir_variable *var = new ir_variable(type, name);
 
+      var->max_array_access = this->max_array_access;
       var->read_only = this->read_only;
       var->centroid = this->centroid;
       var->invariant = this->invariant;
@@ -132,6 +133,13 @@ public:
 
    const char *name;
 
+   /**
+    * Highest element accessed with a constant expression array index
+    *
+    * Not used for non-array variables.
+    */
+   unsigned max_array_access;
+
    unsigned read_only:1;
    unsigned centroid:1;
    unsigned invariant:1;