diff options
author | Juan Linietsky <reduzio@gmail.com> | 2023-01-06 15:05:33 +0100 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2023-01-06 15:05:33 +0100 |
commit | bfc44705998b219d3e6b7f71ec5228696e63bb59 (patch) | |
tree | d1482afe6c12692dce12979fbb5338989e7ee817 | |
parent | b14f7aa9f92ff44135c283a9c88dab5ef9136d64 (diff) |
Prevent recursion in inspector resource assignment.
Fixes #43177
-rw-r--r-- | editor/editor_properties.cpp | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index ba42bbf3bd..3c424a7233 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3847,7 +3847,87 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, } } +static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &resources_found) { + switch (v.get_type()) { + case Variant::ARRAY: { + Array a = v; + for (int i = 0; i < a.size(); i++) { + Variant v2 = a[i]; + if (v2.get_type() != Variant::ARRAY && v2.get_type() != Variant::DICTIONARY && v2.get_type() != Variant::OBJECT) { + continue; + } + if (_find_recursive_resources(v2, resources_found)) { + return true; + } + } + } break; + case Variant::DICTIONARY: { + Dictionary d = v; + List<Variant> keys; + d.get_key_list(&keys); + for (const Variant &k : keys) { + if (k.get_type() == Variant::ARRAY || k.get_type() == Variant::DICTIONARY || k.get_type() == Variant::OBJECT) { + if (_find_recursive_resources(k, resources_found)) { + return true; + } + } + Variant v2 = d[k]; + if (v2.get_type() == Variant::ARRAY || v2.get_type() == Variant::DICTIONARY || v2.get_type() == Variant::OBJECT) { + if (_find_recursive_resources(v2, resources_found)) { + return true; + } + } + } + } break; + case Variant::OBJECT: { + Ref<Resource> r = v; + + if (r.is_null()) { + return false; + } + + if (resources_found.has(r.ptr())) { + return true; + } + + resources_found.insert(r.ptr()); + + List<PropertyInfo> plist; + r->get_property_list(&plist); + for (const PropertyInfo &pinfo : plist) { + if (!(pinfo.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + + if (pinfo.type != Variant::ARRAY && pinfo.type != Variant::DICTIONARY && pinfo.type != Variant::OBJECT) { + continue; + } + if (_find_recursive_resources(r->get(pinfo.name), resources_found)) { + return true; + } + } + } break; + default: { + } + } + return false; +} + void EditorPropertyResource::_resource_changed(const Ref<Resource> &p_resource) { + Resource *r = Object::cast_to<Resource>(get_edited_object()); + if (r) { + // Check for recursive setting of resource + HashSet<Resource *> resources_found; + resources_found.insert(r); + bool found = _find_recursive_resources(p_resource, resources_found); + if (found) { + EditorNode::get_singleton()->show_warning(TTR("Recursion detected, unable to assign resource to property.")); + emit_changed(get_edited_property(), Ref<Resource>()); + update_property(); + return; + } + } + // Make visual script the correct type. Ref<Script> s = p_resource; @@ -3863,7 +3943,7 @@ void EditorPropertyResource::_resource_changed(const Ref<Resource> &p_resource) // Prevent the creation of invalid ViewportTextures when possible. Ref<ViewportTexture> vpt = p_resource; if (vpt.is_valid()) { - Resource *r = Object::cast_to<Resource>(get_edited_object()); + r = Object::cast_to<Resource>(get_edited_object()); if (r && r->get_path().is_resource_file()) { EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on resources saved as a file.\nResource needs to belong to a scene.")); emit_changed(get_edited_property(), Ref<Resource>()); |