diff options
author | Yuri Roubinsky <chaosus89@gmail.com> | 2019-08-28 16:39:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-28 16:39:33 +0300 |
commit | 96ea1e6fb073a32aab2bbefb5eec12769a8435ed (patch) | |
tree | 6e9044c05744b6f65a080238b9f1e85fa0df2bc4 | |
parent | b791efdb1642dcbe0a0572072a176ba39d47c9e1 (diff) | |
parent | 38601dd3e959d09a659b2700cce5e2f2ddbe82a1 (diff) |
Merge pull request #31600 from Chaosus/shader_func_return_fix
Fix shader crash when users miss the return statement
-rw-r--r-- | servers/visual/shader_language.cpp | 59 | ||||
-rw-r--r-- | servers/visual/shader_language.h | 3 |
2 files changed, 62 insertions, 0 deletions
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index e9d85c7eb0..4bc65a8f4f 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -5141,6 +5141,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (err) return err; + if (func_node->return_type != DataType::TYPE_VOID) { + + BlockNode *block = func_node->body; + if (_find_last_flow_op_in_block(block, FlowOperation::FLOW_OP_RETURN) != OK) { + _set_error("Expected at least one return statement in a non-void function."); + return ERR_PARSE_ERROR; + } + } current_function = StringName(); } } @@ -5151,6 +5159,57 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return OK; } +Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op) { + + bool found = false; + + for (int i = p_flow->blocks.size() - 1; i >= 0; i--) { + if (p_flow->blocks[i]->type == Node::TYPE_BLOCK) { + BlockNode *last_block = (BlockNode *)p_flow->blocks[i]; + if (_find_last_flow_op_in_block(last_block, p_op) == OK) { + found = true; + break; + } + } + } + if (found) { + return OK; + } + return FAILED; +} + +Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op) { + + bool found = false; + + for (int i = p_block->statements.size() - 1; i >= 0; i--) { + + if (p_block->statements[i]->type == Node::TYPE_CONTROL_FLOW) { + ControlFlowNode *flow = (ControlFlowNode *)p_block->statements[i]; + if (flow->flow_op == p_op) { + found = true; + break; + } else { + if (_find_last_flow_op_in_op(flow, p_op) == OK) { + found = true; + break; + } + } + } else if (p_block->statements[i]->type == Node::TYPE_BLOCK) { + BlockNode *block = (BlockNode *)p_block->statements[i]; + if (_find_last_flow_op_in_block(block, p_op) == OK) { + found = true; + break; + } + } + } + + if (found) { + return OK; + } + return FAILED; +} + // skips over whitespace and /* */ and // comments static int _get_first_ident_pos(const String &p_code) { diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index b71788513e..6753456323 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -750,6 +750,9 @@ private: Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false); Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types); + Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op); + Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op); + public: //static void get_keyword_list(ShaderType p_type,List<String> *p_keywords); |