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:
@@ -898,13 +898,29 @@ ast_expression::hir(exec_list *instructions,
|
|||||||
|
|
||||||
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
|
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)
|
if (error_emitted)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* FINISHME: Handle vectors and matrices accessed with []. */
|
/* FINISHME: Handle vectors and matrices accessed with []. */
|
||||||
if (!op[0]->type->is_array()) {
|
if (!array->type->is_array()) {
|
||||||
_mesa_glsl_error(& index_loc, state,
|
_mesa_glsl_error(& index_loc, state,
|
||||||
"cannot dereference non-array");
|
"cannot dereference non-array");
|
||||||
error_emitted = true;
|
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
|
* declared size. It is also illegal to index an array with a
|
||||||
* negative constant expression."
|
* negative constant expression."
|
||||||
*/
|
*/
|
||||||
if ((op[0]->type->array_size() > 0)
|
if ((array->type->array_size() > 0)
|
||||||
&& (op[0]->type->array_size() <= idx)) {
|
&& (array->type->array_size() <= idx)) {
|
||||||
_mesa_glsl_error(& loc, state,
|
_mesa_glsl_error(& loc, state,
|
||||||
"array index must be < %u",
|
"array index must be < %u",
|
||||||
op[0]->type->array_size());
|
array->type->array_size());
|
||||||
error_emitted = true;
|
error_emitted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,6 +966,10 @@ ast_expression::hir(exec_list *instructions,
|
|||||||
"array index must be >= 0");
|
"array index must be >= 0");
|
||||||
error_emitted = true;
|
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)
|
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: declarations. It's not 100% clear whether this is
|
||||||
* FINISHME: required or not.
|
* 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;
|
earlier->type = var->type;
|
||||||
delete var;
|
delete var;
|
||||||
var = NULL;
|
var = NULL;
|
||||||
|
2
ir.cpp
2
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_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)
|
mode(ir_var_auto), interpolation(ir_var_smooth)
|
||||||
{
|
{
|
||||||
this->type = type;
|
this->type = type;
|
||||||
|
8
ir.h
8
ir.h
@@ -121,6 +121,7 @@ public:
|
|||||||
{
|
{
|
||||||
ir_variable *var = new ir_variable(type, name);
|
ir_variable *var = new ir_variable(type, name);
|
||||||
|
|
||||||
|
var->max_array_access = this->max_array_access;
|
||||||
var->read_only = this->read_only;
|
var->read_only = this->read_only;
|
||||||
var->centroid = this->centroid;
|
var->centroid = this->centroid;
|
||||||
var->invariant = this->invariant;
|
var->invariant = this->invariant;
|
||||||
@@ -132,6 +133,13 @@ public:
|
|||||||
|
|
||||||
const char *name;
|
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 read_only:1;
|
||||||
unsigned centroid:1;
|
unsigned centroid:1;
|
||||||
unsigned invariant:1;
|
unsigned invariant:1;
|
||||||
|
Reference in New Issue
Block a user