Merge pull request #102792 from clayjohn/varying-crash

Validate varying count when compiling shaders
This commit is contained in:
Thaddeus Crews 2025-02-14 08:25:39 -06:00
commit b607110ad2
No known key found for this signature in database
GPG key ID: 62181B86FE9E5D84
17 changed files with 92 additions and 27 deletions

View file

@ -94,6 +94,8 @@ public:
virtual String get_video_adapter_api_version() const override { return String(); }
virtual Size2i get_maximum_viewport_size() const override { return Size2i(); }
virtual uint32_t get_maximum_shader_varyings() const override { return 31; } // Fair assumption for everything except old OpenGL-only phones.
virtual uint64_t get_maximum_uniform_buffer_size() const override { return 65536; } // Fair assumption for all devices.
};
} // namespace RendererDummy

View file

@ -329,3 +329,11 @@ Size2i Utilities::get_maximum_viewport_size() const {
int max_y = device->limit_get(RenderingDevice::LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);
return Size2i(max_x, max_y);
}
uint32_t Utilities::get_maximum_shader_varyings() const {
return RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_SHADER_VARYINGS);
}
uint64_t Utilities::get_maximum_uniform_buffer_size() const {
return RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
}

View file

@ -117,6 +117,8 @@ public:
virtual String get_video_adapter_api_version() const override;
virtual Size2i get_maximum_viewport_size() const override;
virtual uint32_t get_maximum_shader_varyings() const override;
virtual uint64_t get_maximum_uniform_buffer_size() const override;
};
} // namespace RendererRD

View file

@ -875,6 +875,7 @@ public:
LIMIT_VRS_MAX_FRAGMENT_HEIGHT,
LIMIT_METALFX_TEMPORAL_SCALER_MIN_SCALE,
LIMIT_METALFX_TEMPORAL_SCALER_MAX_SCALE,
LIMIT_MAX_SHADER_VARYINGS,
};
enum Features {

View file

@ -686,30 +686,14 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
vcode += _prestr(varying.precision, ShaderLanguage::is_float_type(varying.type));
vcode += _typestr(varying.type);
vcode += " " + _mkid(varying_name);
uint32_t inc = 1U;
uint32_t inc = varying.get_size();
if (varying.array_size > 0) {
inc = (uint32_t)varying.array_size;
vcode += "[";
vcode += itos(varying.array_size);
vcode += "]";
}
switch (varying.type) {
case SL::TYPE_MAT2:
inc *= 2U;
break;
case SL::TYPE_MAT3:
inc *= 3U;
break;
case SL::TYPE_MAT4:
inc *= 4U;
break;
default:
break;
}
vcode += ";\n";
// GLSL ES 3.0 does not allow layout qualifiers for varyings
if (!RS::get_singleton()->is_low_end()) {
@ -1481,6 +1465,7 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
info.render_modes = ShaderTypes::get_singleton()->get_modes(p_mode);
info.shader_types = ShaderTypes::get_singleton()->get_types();
info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
info.base_varying_index = actions.base_varying_index;
Error err = parser.compile(p_code, info);

View file

@ -33,6 +33,7 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
#include "shader_types.h"
@ -9111,17 +9112,12 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
int prop_index = 0;
#ifdef DEBUG_ENABLED
uint64_t uniform_buffer_size = 0;
uint64_t max_uniform_buffer_size = 0;
uint64_t max_uniform_buffer_size = 65536;
int uniform_buffer_exceeded_line = -1;
bool check_device_limit_warnings = false;
{
RenderingDevice *device = RenderingDevice::get_singleton();
if (device != nullptr) {
check_device_limit_warnings = check_warnings && HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
max_uniform_buffer_size = device->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
}
bool check_device_limit_warnings = check_warnings && HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
// Can be false for internal shaders created in the process of initializing the engine.
if (RSG::utilities) {
max_uniform_buffer_size = RSG::utilities->get_maximum_uniform_buffer_size();
}
#endif // DEBUG_ENABLED
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@ -10959,6 +10955,12 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
tk = _get_token();
}
uint32_t varying_index = base_varying_index;
uint32_t max_varyings = 31;
// Can be false for internal shaders created in the process of initializing the engine.
if (RSG::utilities) {
max_varyings = RSG::utilities->get_maximum_shader_varyings();
}
for (const KeyValue<StringName, ShaderNode::Varying> &kv : shader->varyings) {
if (kv.value.stage != ShaderNode::Varying::STAGE_FRAGMENT && (kv.value.type > TYPE_BVEC4 && kv.value.type < TYPE_FLOAT) && kv.value.interpolation != INTERPOLATION_FLAT) {
@ -10966,6 +10968,14 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
_set_error(vformat(RTR("Varying with integer data type must be declared with `%s` interpolation qualifier."), "flat"));
return ERR_PARSE_ERROR;
}
if (varying_index + kv.value.get_size() > max_varyings) {
_set_tkpos(kv.value.tkpos);
_set_error(vformat(RTR("Too many varyings used in shader (%d used, maximum supported is %d)."), varying_index + kv.value.get_size(), max_varyings));
return ERR_PARSE_ERROR;
}
varying_index += kv.value.get_size();
}
#ifdef DEBUG_ENABLED
@ -11183,6 +11193,7 @@ Error ShaderLanguage::compile(const String &p_code, const ShaderCompileInfo &p_i
global_shader_uniform_get_type_func = p_info.global_shader_uniform_type_func;
varying_function_names = p_info.varying_function_names;
base_varying_index = p_info.base_varying_index;
nodes = nullptr;

View file

@ -631,6 +631,28 @@ public:
int array_size = 0;
TkPos tkpos;
uint32_t get_size() const {
uint32_t size = 1;
if (array_size > 0) {
size = (uint32_t)array_size;
}
switch (type) {
case TYPE_MAT2:
size *= 2;
break;
case TYPE_MAT3:
size *= 3;
break;
case TYPE_MAT4:
size *= 4;
break;
default:
break;
}
return size;
}
Varying() {}
};
@ -1022,6 +1044,7 @@ private:
String current_uniform_subgroup_name;
VaryingFunctionNames varying_function_names;
uint32_t base_varying_index = 0;
TkPos _get_tkpos() {
TkPos tkp;
@ -1217,6 +1240,7 @@ public:
HashSet<String> shader_types;
GlobalShaderUniformGetTypeFunc global_shader_uniform_type_func = nullptr;
bool is_include = false;
uint32_t base_varying_index = 0;
};
Error compile(const String &p_code, const ShaderCompileInfo &p_info);

View file

@ -184,6 +184,8 @@ public:
virtual String get_video_adapter_api_version() const = 0;
virtual Size2i get_maximum_viewport_size() const = 0;
virtual uint32_t get_maximum_shader_varyings() const = 0;
virtual uint64_t get_maximum_uniform_buffer_size() const = 0;
};
#endif // RENDERER_UTILITIES_H