From d2e642b2dc088486ac040c64dbc008dbf918f534 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 14 Nov 2018 18:55:38 -0300 Subject: [PATCH] Proper validation of out arguments in built-in shader functions, closes #16244 --- servers/visual/shader_language.cpp | 41 ++++++++++++++++++++++++++++++ servers/visual/shader_language.h | 8 ++++++ 2 files changed, 49 insertions(+) diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 3fe661090c9..0783d91a591 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2037,6 +2037,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { }; +const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { + //constructors + { "modf", 1 }, + { NULL, 0 } +}; + bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type) { ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, NULL); @@ -2080,6 +2086,41 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p if (!fail) { + //make sure its not an out argument used in the wrong way + int outarg_idx = 0; + while (builtin_func_out_args[outarg_idx].name) { + + if (String(name) == builtin_func_out_args[outarg_idx].name) { + int arg_idx = builtin_func_out_args[outarg_idx].argument; + + if (arg_idx < argcount) { + + if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable"); + return false; + } + StringName var_name = static_cast(p_func->arguments[arg_idx + 1])->name; + + const BlockNode *b = p_block; + bool valid = false; + while (b) { + if (b->variables.has(var_name)) { + valid = true; + break; + } + b = b->parent_block; + } + + if (!valid) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable"); + return false; + } + } + } + + outarg_idx++; + } + if (r_ret_type) *r_ret_type = builtin_func_defs[idx].rettype; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index f07b1fade5d..9277dfa2cfa 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -333,6 +333,7 @@ public: virtual DataType get_datatype() const { return datatype_cache; } VariableNode() { + type = TYPE_VARIABLE; datatype_cache = TYPE_VOID; } @@ -643,6 +644,12 @@ private: const DataType args[MAX_ARGS]; }; + struct BuiltinFuncOutArgs { //arguments used as out in built in funcions + + const char *name; + int argument; + }; + CompletionType completion_type; int completion_line; BlockNode *completion_block; @@ -653,6 +660,7 @@ private: bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); static const BuiltinFuncDef builtin_func_defs[]; + static const BuiltinFuncOutArgs builtin_func_out_args[]; bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type); bool _parse_function_arguments(BlockNode *p_block, const Map &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL);