summaryrefslogtreecommitdiff
path: root/servers/visual/shader_language.cpp
diff options
context:
space:
mode:
authorYuri Roubinski <chaosus89@gmail.com>2019-08-23 15:40:42 +0300
committerChaosus89 <chaosus89@gmail.com>2019-08-28 11:32:33 +0300
commit38601dd3e959d09a659b2700cce5e2f2ddbe82a1 (patch)
tree8ec906cdc77f46f5244cfda150117d70119f5c3c /servers/visual/shader_language.cpp
parentc59da91aad4c73c68e5e2884674f5fb3c3340751 (diff)
Fix shader crash when users miss the return statement
Diffstat (limited to 'servers/visual/shader_language.cpp')
-rw-r--r--servers/visual/shader_language.cpp59
1 files changed, 59 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) {