From 516aa46fe565180b2c59d7753ee835a7e716c225 Mon Sep 17 00:00:00 2001 From: Yuri Roubinsky Date: Wed, 12 Feb 2020 23:16:47 +0300 Subject: Fix shader crash if pass const argument to 'out/inout' parameter --- servers/visual/shader_language.cpp | 115 ++++++++++++++++++++++++++++--------- servers/visual/shader_language.h | 3 + 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 2a0492709c..a5b028b15b 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -903,6 +903,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Maparguments.size(); i++) { int argidx = i + 1; - if (argidx < func->arguments.size() && is_sampler_type(call_function->arguments[i].type)) { - //let's see where our argument comes from - Node *n = func->arguments[argidx]; - ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable - VariableNode *vn = static_cast(n); - StringName varname = vn->name; - if (shader->uniforms.has(varname)) { - //being sampler, this either comes from a uniform - ShaderNode::Uniform *u = &shader->uniforms[varname]; - ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously - //propagate - if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) { - return NULL; + if (argidx < func->arguments.size()) { + if (call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { + bool error = false; + Node *n = func->arguments[argidx]; + if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { + error = true; + } else if (n->type == Node::TYPE_ARRAY) { + ArrayNode *an = static_cast(n); + if (an->call_expression != NULL) { + error = true; + } + } else if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast(n); + if (vn->is_const) { + error = true; + } else { + StringName varname = vn->name; + if (shader->uniforms.has(varname)) { + error = true; + } else { + if (p_builtin_types.has(varname)) { + BuiltInInfo info = p_builtin_types[varname]; + if (info.constant) { + error = true; + } + } + } + } + } else if (n->type == Node::TYPE_MEMBER) { + MemberNode *mn = static_cast(n); + if (mn->basetype_const) { + error = true; + } } - } else if (p_builtin_types.has(varname)) { - //a built-in - if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) { + if (error) { + _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier))); return NULL; } - } else { - //or this comes from an argument, but nothing else can be a sampler - bool found = false; - for (int j = 0; j < base_function->arguments.size(); j++) { - if (base_function->arguments[j].name == varname) { - if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) { - base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set(); + } + if (is_sampler_type(call_function->arguments[i].type)) { + //let's see where our argument comes from + Node *n = func->arguments[argidx]; + ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable + VariableNode *vn = static_cast(n); + StringName varname = vn->name; + if (shader->uniforms.has(varname)) { + //being sampler, this either comes from a uniform + ShaderNode::Uniform *u = &shader->uniforms[varname]; + ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously + //propagate + if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) { + return NULL; + } + } else if (p_builtin_types.has(varname)) { + //a built-in + if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) { + return NULL; + } + } else { + //or this comes from an argument, but nothing else can be a sampler + bool found = false; + for (int j = 0; j < base_function->arguments.size(); j++) { + if (base_function->arguments[j].name == varname) { + if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) { + base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set(); + } + base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i); + found = true; + break; } - base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i); - found = true; - break; } + ERR_CONTINUE(!found); } - ERR_CONTINUE(!found); } + } else { + break; } } } @@ -3504,7 +3551,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons DataType data_type; IdentifierType ident_type; - bool is_const = false; int array_size = 0; StringName struct_name; @@ -3812,6 +3858,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons MemberNode *mn = alloc_node(); mn->basetype = dt; + mn->basetype_const = is_const; mn->datatype = member_type; mn->base_struct_name = st; mn->struct_name = member_struct_name; @@ -5359,6 +5406,18 @@ String ShaderLanguage::_get_shader_type_list(const Set &p_shader_types) return valid_types; } +String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const { + switch (p_qualifier) { + case ArgumentQualifier::ARGUMENT_QUALIFIER_IN: + return "in"; + case ArgumentQualifier::ARGUMENT_QUALIFIER_OUT: + return "out"; + case ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT: + return "inout"; + } + return ""; +} + Error ShaderLanguage::_validate_datatype(DataType p_type) { if (VisualServer::get_singleton()->is_low_end()) { bool invalid_type = false; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index aac5795e85..e56fb35a8b 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -529,6 +529,7 @@ public: struct MemberNode : public Node { DataType basetype; + bool basetype_const; StringName base_struct_name; DataPrecision precision; DataType datatype; @@ -544,6 +545,7 @@ public: MemberNode() : Node(TYPE_MEMBER), basetype(TYPE_VOID), + basetype_const(false), datatype(TYPE_VOID), array_size(0), owner(NULL), @@ -866,6 +868,7 @@ private: Node *_parse_and_reduce_expression(BlockNode *p_block, const Map &p_builtin_types); Error _parse_block(BlockNode *p_block, const Map &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false); String _get_shader_type_list(const Set &p_shader_types) const; + String _get_qualifier_str(ArgumentQualifier p_qualifier) const; Error _parse_shader(const Map &p_functions, const Vector &p_render_modes, const Set &p_shader_types); -- cgit v1.2.3