summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
authorYuri Roubinsky <chaosus89@gmail.com>2022-04-26 11:46:06 +0300
committerYuri Roubinsky <chaosus89@gmail.com>2022-04-26 12:30:24 +0300
commit643e75bea99108a503fb27229cfcc108bd533a8f (patch)
treee9fa854aeb63cf6548cdd06fd611531ccabd969c /servers
parent06c33cca18d81bc0976c512a0f6b608780fad958 (diff)
Prevent shader crash when using precision on boolean types
Diffstat (limited to 'servers')
-rw-r--r--servers/rendering/shader_language.cpp141
-rw-r--r--servers/rendering/shader_language.h1
2 files changed, 79 insertions, 63 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index af5da6ae6f..54d1a6fd8d 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -4670,16 +4670,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = _parse_array_constructor(p_block, p_function_info);
} else {
DataType datatype;
- DataPrecision precision;
- bool precision_defined = false;
+ DataPrecision precision = PRECISION_DEFAULT;
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- precision_defined = true;
tk = _get_token();
}
datatype = get_token_datatype(tk.type);
+ if (precision != PRECISION_DEFAULT && _validate_precision(datatype, precision) != OK) {
+ return nullptr;
+ }
+
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
@@ -4697,7 +4699,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_CONSTRUCT;
- if (precision_defined) {
+ if (precision != PRECISION_DEFAULT) {
func->return_precision_cache = precision;
}
@@ -6426,10 +6428,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!is_struct) {
is_struct = shader->structs.has(tk.text); // check again.
}
- if (is_struct && precision != PRECISION_DEFAULT) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
if (!is_token_nonvoid_datatype(tk.type)) {
_set_error(RTR("Expected variable type after precision modifier."));
return ERR_PARSE_ERROR;
@@ -6449,6 +6447,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
int array_size = 0;
bool fixed_array_size = false;
bool first = true;
@@ -6600,10 +6602,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (is_token_precision(tk.type)) {
precision2 = get_token_precision(tk.type);
tk = _get_token();
- if (shader->structs.has(tk.text)) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
if (!is_token_nonvoid_datatype(tk.type)) {
_set_error(RTR("Expected data type after precision modifier."));
return ERR_PARSE_ERROR;
@@ -6624,6 +6622,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
type2 = get_token_datatype(tk.type);
}
+ if (precision2 != PRECISION_DEFAULT && _validate_precision(type2, precision2) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
int array_size2 = 0;
tk = _get_token();
@@ -7427,6 +7429,25 @@ String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
return "";
}
+Error ShaderLanguage::_validate_precision(DataType p_type, DataPrecision p_precision) {
+ switch (p_type) {
+ case TYPE_STRUCT: {
+ _set_error(RTR("The precision modifier cannot be used on structs."));
+ return FAILED;
+ } break;
+ case TYPE_BOOL:
+ case TYPE_BVEC2:
+ case TYPE_BVEC3:
+ case TYPE_BVEC4: {
+ _set_error(RTR("The precision modifier cannot be used on boolean types."));
+ return FAILED;
+ } break;
+ default:
+ break;
+ }
+ return OK;
+}
+
Error ShaderLanguage::_validate_datatype(DataType p_type) {
if (RenderingServer::get_singleton()->is_low_end()) {
bool invalid_type = false;
@@ -7608,8 +7629,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
StringName struct_name = "";
bool struct_dt = false;
- bool use_precision = false;
- DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
+ DataPrecision precision = PRECISION_DEFAULT;
if (tk.type == TK_STRUCT) {
_set_error(RTR("Nested structs are not allowed."));
@@ -7618,7 +7638,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- use_precision = true;
tk = _get_token();
}
@@ -7630,10 +7649,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
#endif // DEBUG_ENABLED
struct_dt = true;
- if (use_precision) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
}
if (!is_token_datatype(tk.type) && !struct_dt) {
@@ -7642,6 +7657,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
if (type == TYPE_VOID || is_sampler_type(type)) {
_set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type)));
return ERR_PARSE_ERROR;
@@ -7762,7 +7781,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
}
- bool precision_defined = false;
DataPrecision precision = PRECISION_DEFAULT;
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
DataType type;
@@ -7781,16 +7799,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- precision_defined = true;
tk = _get_token();
}
if (shader->structs.has(tk.text)) {
if (uniform) {
- if (precision_defined) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
return ERR_PARSE_ERROR;
} else {
@@ -7806,6 +7819,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
type = get_token_datatype(tk.type);
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
if (type == TYPE_VOID) {
_set_error(vformat(RTR("The '%s' data type is not allowed here."), "void"));
return ERR_PARSE_ERROR;
@@ -8249,10 +8266,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (shader->structs.has(tk.text)) {
- if (precision != PRECISION_DEFAULT) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
is_struct = true;
struct_name = tk.text;
} else {
@@ -8276,6 +8289,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
type = get_token_datatype(tk.type);
}
+
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
prev_pos = _get_tkpos();
tk = _get_token();
@@ -8652,44 +8670,41 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
break;
}
- bool is_const = false;
+ bool param_is_const = false;
if (tk.type == TK_CONST) {
- is_const = true;
+ param_is_const = true;
tk = _get_token();
}
- ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
-
+ ArgumentQualifier param_qualifier = ARGUMENT_QUALIFIER_IN;
if (tk.type == TK_ARG_IN) {
- qualifier = ARGUMENT_QUALIFIER_IN;
+ param_qualifier = ARGUMENT_QUALIFIER_IN;
tk = _get_token();
} else if (tk.type == TK_ARG_OUT) {
- if (is_const) {
+ if (param_is_const) {
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const"));
return ERR_PARSE_ERROR;
}
- qualifier = ARGUMENT_QUALIFIER_OUT;
+ param_qualifier = ARGUMENT_QUALIFIER_OUT;
tk = _get_token();
} else if (tk.type == TK_ARG_INOUT) {
- if (is_const) {
+ if (param_is_const) {
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const"));
return ERR_PARSE_ERROR;
}
- qualifier = ARGUMENT_QUALIFIER_INOUT;
+ param_qualifier = ARGUMENT_QUALIFIER_INOUT;
tk = _get_token();
}
- DataType ptype;
- StringName pname;
+ DataType param_type;
+ StringName param_name;
StringName param_struct_name;
- DataPrecision pprecision = PRECISION_DEFAULT;
- bool use_precision = false;
+ DataPrecision param_precision = PRECISION_DEFAULT;
int arg_array_size = 0;
if (is_token_precision(tk.type)) {
- pprecision = get_token_precision(tk.type);
+ param_precision = get_token_precision(tk.type);
tk = _get_token();
- use_precision = true;
}
is_struct = false;
@@ -8702,10 +8717,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
used_structs[param_struct_name].used = true;
}
#endif // DEBUG_ENABLED
- if (use_precision) {
- _set_error(RTR("The precision modifier cannot be used on structs."));
- return ERR_PARSE_ERROR;
- }
}
if (!is_struct && !is_token_datatype(tk.type)) {
@@ -8713,7 +8724,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
+ if (param_qualifier == ARGUMENT_QUALIFIER_OUT || param_qualifier == ARGUMENT_QUALIFIER_INOUT) {
if (is_sampler_type(get_token_datatype(tk.type))) {
_set_error(RTR("Opaque types cannot be output parameters."));
return ERR_PARSE_ERROR;
@@ -8721,18 +8732,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (is_struct) {
- ptype = TYPE_STRUCT;
+ param_type = TYPE_STRUCT;
} else {
- ptype = get_token_datatype(tk.type);
- if (_validate_datatype(ptype) != OK) {
+ param_type = get_token_datatype(tk.type);
+ if (_validate_datatype(param_type) != OK) {
return ERR_PARSE_ERROR;
}
- if (ptype == TYPE_VOID) {
+ if (param_type == TYPE_VOID) {
_set_error(RTR("Void type not allowed as argument."));
return ERR_PARSE_ERROR;
}
}
+ if (param_precision != PRECISION_DEFAULT && _validate_precision(param_type, param_precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
@@ -8747,32 +8762,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- pname = tk.text;
+ param_name = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(func_node->body, false, builtins, param_name, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
- _set_redefinition_error(String(pname));
+ _set_redefinition_error(String(param_name));
return ERR_PARSE_ERROR;
}
}
- if (has_builtin(p_functions, pname)) {
- _set_redefinition_error(String(pname));
+ if (has_builtin(p_functions, param_name)) {
+ _set_redefinition_error(String(param_name));
return ERR_PARSE_ERROR;
}
FunctionNode::Argument arg;
- arg.type = ptype;
- arg.name = pname;
+ arg.type = param_type;
+ arg.name = param_name;
arg.type_str = param_struct_name;
- arg.precision = pprecision;
- arg.qualifier = qualifier;
+ arg.precision = param_precision;
+ arg.qualifier = param_qualifier;
arg.tex_argument_check = false;
arg.tex_builtin_check = false;
arg.tex_argument_filter = FILTER_DEFAULT;
arg.tex_argument_repeat = REPEAT_DEFAULT;
- arg.is_const = is_const;
+ arg.is_const = param_is_const;
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 66ae220edf..de6d912a4f 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -1038,6 +1038,7 @@ private:
static bool is_const_suffix_lut_initialized;
+ Error _validate_precision(DataType p_type, DataPrecision p_precision);
Error _validate_datatype(DataType p_type);
bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
bool _compare_datatypes_in_nodes(Node *a, Node *b);