Prevent shader crash when using precision on boolean types

This commit is contained in:
Yuri Roubinsky 2022-04-26 11:46:06 +03:00
parent 06c33cca18
commit 643e75bea9
2 changed files with 79 additions and 63 deletions

View file

@ -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) {

View file

@ -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);