From ea489c40680f9e8e90eeb163d17c8dddd53981d4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 7 Apr 2021 15:28:24 +0300 Subject: [PATCH] Check that non-constant data is not accessed from constant expressions --- source/glsl/validate.cpp | 42 ++++++++++++++++++++++++---- source/glsl/validate.h | 3 ++ tests/glsl/constant_expressions.glsl | 15 ++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 tests/glsl/constant_expressions.glsl diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 4a5ffe84..62f997bb 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -508,9 +508,22 @@ void ReferenceValidator::visit(FunctionDeclaration &func) ExpressionValidator::ExpressionValidator(): - current_function(0) + current_function(0), + constant_expression(false) { } +void ExpressionValidator::visit(VariableReference &var) +{ + if(var.declaration && constant_expression && !var.declaration->constant) + error(var, format("Reference to non-constant variable '%s' in a constant expression", var.name)); +} + +void ExpressionValidator::visit(InterfaceBlockReference &iface) +{ + if(constant_expression) + error(iface, format("Reference to interface block '%s' in a constant expression", iface.name)); +} + void ExpressionValidator::visit(Swizzle &swizzle) { unsigned size = 0; @@ -555,8 +568,13 @@ void ExpressionValidator::visit(UnaryExpression &unary) { if(!unary.type) error(unary, format("No matching operator '%s' found for '%s'", unary.oper->token, unary.expression->type->name)); - else if((unary.oper->token[1]=='+' || unary.oper->token[1]=='-') && !unary.expression->lvalue) - error(unary, format("Operand of '%s' is not an lvalue", unary.oper->token)); + else if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-') + { + if(constant_expression) + error(unary, format("Use of '%s' in a constant expression", unary.oper->token)); + else if(!unary.expression->lvalue) + error(unary, format("Operand of '%s' is not an lvalue", unary.oper->token)); + } } TraversingVisitor::visit(unary); } @@ -579,7 +597,9 @@ void ExpressionValidator::visit(Assignment &assign) { if(assign.left->type) { - if(!assign.left->lvalue) + if(constant_expression) + error(assign, "Assignment in constant expression"); + else if(!assign.left->lvalue) error(assign, "Target of assignment is not an lvalue"); if(assign.right->type) { @@ -616,7 +636,19 @@ void ExpressionValidator::visit(VariableDeclaration &var) if(var.init_expression && var.init_expression->type && var.type_declaration && var.init_expression->type!=var.type_declaration) error(var, format("Initializing a variable of type '%s' with an expression of incompatible type '%s'", var.type_declaration->name, var.init_expression->type->name)); - TraversingVisitor::visit(var); + + if(var.layout) + var.layout->visit(*this); + if(var.init_expression) + { + SetFlag set_const(constant_expression, var.constant); + TraversingVisitor::visit(var.init_expression); + } + if(var.array_size) + { + SetFlag set_const(constant_expression); + TraversingVisitor::visit(var.array_size); + } } void ExpressionValidator::visit(FunctionDeclaration &func) diff --git a/source/glsl/validate.h b/source/glsl/validate.h index 1a058170..fe52ff5a 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -118,6 +118,7 @@ class ExpressionValidator: private Validator { private: FunctionDeclaration *current_function; + bool constant_expression; public: ExpressionValidator(); @@ -125,6 +126,8 @@ public: void apply(Stage &s) { stage = &s; s.content.visit(*this); } private: + virtual void visit(VariableReference &); + virtual void visit(InterfaceBlockReference &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); diff --git a/tests/glsl/constant_expressions.glsl b/tests/glsl/constant_expressions.glsl new file mode 100644 index 00000000..90eab787 --- /dev/null +++ b/tests/glsl/constant_expressions.glsl @@ -0,0 +1,15 @@ +uniform int n_lights; +uniform vec3 light_dir[n_lights]; + +#pragma MSP stage(vertex) +layout(location=0) in vec4 position; +const bool lower_half = position.y<0; +void main() +{ + gl_Position = position; +} + +/* Expected error: +:2: Reference to non-constant variable 'n_lights' in a constant expression +:6: Reference to non-constant variable 'position' in a constant expression +*/ -- 2.45.2