summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuri Roubinsky <chaosus89@gmail.com>2019-08-28 16:39:33 +0300
committerGitHub <noreply@github.com>2019-08-28 16:39:33 +0300
commit96ea1e6fb073a32aab2bbefb5eec12769a8435ed (patch)
tree6e9044c05744b6f65a080238b9f1e85fa0df2bc4
parentb791efdb1642dcbe0a0572072a176ba39d47c9e1 (diff)
parent38601dd3e959d09a659b2700cce5e2f2ddbe82a1 (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.cpp59
-rw-r--r--servers/visual/shader_language.h3
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);