From 0f047944e4b34483c8f2b9e529e8ecbd36dbef2d Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Thu, 23 Oct 2025 22:30:54 +0200 Subject: [PATCH] Statically protect `Object::cast_to` for unrelated `Object` types. Fix a handful of bugs associated with it. --- core/io/dir_access.cpp | 4 +- core/object/object.h | 53 ++++++++++++--------- editor/export/editor_export_platform.cpp | 2 +- editor/import/3d/scene_import_settings.cpp | 4 +- editor/inspector/editor_preview_plugins.cpp | 4 +- editor/scene/3d/node_3d_editor_plugin.cpp | 2 +- modules/gltf/gltf_document.cpp | 20 -------- scene/resources/audio_stream_polyphonic.cpp | 2 +- 8 files changed, 40 insertions(+), 51 deletions(-) diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index cd46a5a3d11..fde1fbb7969 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -326,7 +326,7 @@ Ref DirAccess::create_temp(const String &p_prefix, bool p_keep, Error if (!p_prefix.is_valid_filename()) { *r_error = ERR_FILE_BAD_PATH; - ERR_FAIL_V_MSG(Ref(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix)); + ERR_FAIL_V_MSG(Ref(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix)); } Ref dir_access = DirAccess::open(OS::get_singleton()->get_temp_path()); @@ -351,7 +351,7 @@ Ref DirAccess::create_temp(const String &p_prefix, bool p_keep, Error Error err = dir_access->make_dir(path); if (err != OK) { *r_error = err; - ERR_FAIL_V_MSG(Ref(), vformat(R"(%s: "%s" couldn't create directory "%s".)", ERROR_COMMON_PREFIX, path)); + ERR_FAIL_V_MSG(Ref(), vformat(R"(%s: "%s" couldn't create directory "%s".)", ERROR_COMMON_PREFIX, path)); } err = dir_access->change_dir(path); if (err != OK) { diff --git a/core/object/object.h b/core/object/object.h index aeb8c752a06..6d611642cb2 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -829,16 +829,27 @@ public: void detach_from_objectdb(); _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; } - template - static T *cast_to(Object *p_object) { + template + static T *cast_to(O *p_object) { // This is like dynamic_cast, but faster. // The reason is that we can assume no virtual and multiple inheritance. - return p_object && p_object->derives_from() ? static_cast(p_object) : nullptr; + return p_object && p_object->template derives_from() ? static_cast(p_object) : nullptr; + } + + template + static const T *cast_to(const O *p_object) { + return p_object && p_object->template derives_from() ? static_cast(p_object) : nullptr; + } + + // cast_to versions for types that implicitly convert to Object. + template + static T *cast_to(Object *p_object) { + return p_object && p_object->template derives_from() ? static_cast(p_object) : nullptr; } template static const T *cast_to(const Object *p_object) { - return p_object && p_object->derives_from() ? static_cast(p_object) : nullptr; + return p_object && p_object->template derives_from() ? static_cast(p_object) : nullptr; } enum { @@ -871,7 +882,7 @@ public: bool is_class(const String &p_class) const; virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } - template + template bool derives_from() const; const StringName &get_class_name() const; @@ -1040,29 +1051,25 @@ public: bool predelete_handler(Object *p_object); void postinitialize_handler(Object *p_object); -template +template bool Object::derives_from() const { - static_assert(std::is_base_of_v, "T must be derived from Object."); - static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS."); - - // If there is an explicitly set ancestral class on the type, we can use that. - if constexpr (T::static_ancestral_class != T::super_type::static_ancestral_class) { - return _has_ancestry(T::static_ancestral_class); + if constexpr (std::is_base_of_v) { + // We derive statically from T (or are the same class), so casting to it is trivial. + return true; } else { - return is_class_ptr(T::get_class_ptr_static()); + static_assert(std::is_base_of_v, "derives_from can only be used with Object subclasses."); + static_assert(std::is_base_of_v, "Cannot cast argument to T because T does not derive from the argument's known class."); + static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS."); + + // If there is an explicitly set ancestral class on the type, we can use that. + if constexpr (T::static_ancestral_class != T::super_type::static_ancestral_class) { + return _has_ancestry(T::static_ancestral_class); + } else { + return is_class_ptr(T::get_class_ptr_static()); + } } } -template <> -inline bool Object::derives_from() const { - return true; -} - -template <> -inline bool Object::derives_from() const { - return true; -} - class ObjectDB { // This needs to add up to 63, 1 bit is for reference. #define OBJECTDB_VALIDATOR_BITS 39 diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 1857b6941fe..a5c37480b59 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -645,7 +645,7 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() { export_plugins.write[i]->_export_end(); } export_plugins.write[i]->_export_end_clear(); - export_plugins.write[i]->set_export_preset(Ref()); + export_plugins.write[i]->set_export_preset(Ref()); } } diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index 824dbd9c4f2..25199d41299 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -1131,7 +1131,9 @@ void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value) void SceneImportSettingsDialog::_skeleton_tree_entered(Skeleton3D *p_skeleton) { bones_mesh_preview->set_skeleton_path(p_skeleton->get_path()); - bones_mesh_preview->set_skin(p_skeleton->register_skin(p_skeleton->create_skin_from_rest_transforms())); + Ref skin = p_skeleton->create_skin_from_rest_transforms(); + p_skeleton->register_skin(skin); + bones_mesh_preview->set_skin(skin); } void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) { diff --git a/editor/inspector/editor_preview_plugins.cpp b/editor/inspector/editor_preview_plugins.cpp index 779a7a7cc83..9afc324b2b1 100644 --- a/editor/inspector/editor_preview_plugins.cpp +++ b/editor/inspector/editor_preview_plugins.cpp @@ -192,7 +192,7 @@ Ref EditorImagePreviewPlugin::generate(const Ref &p_from, c Ref img = p_from; if (img.is_null() || img->is_empty()) { - return Ref(); + return Ref(); } img = img->duplicate(); @@ -200,7 +200,7 @@ Ref EditorImagePreviewPlugin::generate(const Ref &p_from, c if (img->is_compressed()) { if (img->decompress() != OK) { - return Ref(); + return Ref(); } } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) { img->convert(Image::FORMAT_RGBA8); diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp index ab4dd568d41..6934876bfc3 100644 --- a/editor/scene/3d/node_3d_editor_plugin.cpp +++ b/editor/scene/3d/node_3d_editor_plugin.cpp @@ -497,7 +497,7 @@ void ViewportRotationControl::gui_input(const Ref &p_event) { const Ref screen_drag = p_event; if (screen_drag.is_valid()) { - _process_drag(screen_drag, screen_drag->get_index(), screen_drag->get_position(), screen_drag->get_relative()); + _process_drag(nullptr, screen_drag->get_index(), screen_drag->get_position(), screen_drag->get_relative()); } } diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index a3d01853b4f..652ffdbd168 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2143,10 +2143,6 @@ Dictionary GLTFDocument::_serialize_image(Ref p_state, Ref p_i bv->byte_offset = p_state->buffers[bi].size(); Vector buffer; - Ref img_tex = p_image; - if (img_tex.is_valid()) { - p_image = img_tex->get_image(); - } // Save in various image formats. Note that if the format is "None", // the state's images will be empty, so this code will not be reached. if (_image_save_extension.is_valid()) { @@ -2755,10 +2751,6 @@ Error GLTFDocument::_serialize_materials(Ref p_state) { height = ao_texture->get_height(); width = ao_texture->get_width(); ao_image = ao_texture->get_image(); - Ref img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } if (ao_image->is_compressed()) { ao_image->decompress(); } @@ -2771,10 +2763,6 @@ Error GLTFDocument::_serialize_materials(Ref p_state) { height = roughness_texture->get_height(); width = roughness_texture->get_width(); roughness_image = roughness_texture->get_image(); - Ref img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } if (roughness_image->is_compressed()) { roughness_image->decompress(); } @@ -2787,10 +2775,6 @@ Error GLTFDocument::_serialize_materials(Ref p_state) { height = metallic_texture->get_height(); width = metallic_texture->get_width(); metallness_image = metallic_texture->get_image(); - Ref img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } if (metallness_image->is_compressed()) { metallness_image->decompress(); } @@ -2903,10 +2887,6 @@ Error GLTFDocument::_serialize_materials(Ref p_state) { // Code for uncompressing RG normal maps Ref img = normal_texture->get_image(); if (img.is_valid()) { - Ref img_tex = normal_texture; - if (img_tex.is_valid()) { - img = img_tex->get_image(); - } img->decompress(); img->convert(Image::FORMAT_RGBA8); for (int32_t y = 0; y < img->get_height(); y++) { diff --git a/scene/resources/audio_stream_polyphonic.cpp b/scene/resources/audio_stream_polyphonic.cpp index 994f1b81197..3da9106e35e 100644 --- a/scene/resources/audio_stream_polyphonic.cpp +++ b/scene/resources/audio_stream_polyphonic.cpp @@ -255,7 +255,7 @@ AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(con sp->bus = p_bus; if (streams[i].stream_playback->get_sample_playback().is_valid()) { - AudioServer::get_singleton()->stop_playback_stream(sp); + AudioServer::get_singleton()->stop_playback_stream(streams[i].stream_playback); } streams[i].stream_playback->set_sample_playback(sp);