Track max accessed array element, reject additional out-of-bounds accesses

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
This commit is contained in:
Ian Romanick 2010-04-01 18:31:11 -07:00
parent 27e3cf8c0d
commit b8a21cc6df
3 changed files with 43 additions and 9 deletions

View 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;

2
ir.cpp
View File

@ -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;

8
ir.h
View File

@ -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;