فهرست منبع

Merge pull request #111967 from Ivorforce/object-cast-to-protect

Statically protect `Object::cast_to` for unrelated `Object` types.
Thaddeus Crews 2 هفته پیش
والد
کامیت
6e69760134

+ 2 - 2
core/io/dir_access.cpp

@@ -326,7 +326,7 @@ Ref<DirAccess> 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<FileAccess>(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix));
+		ERR_FAIL_V_MSG(Ref<DirAccess>(), vformat(R"(%s: "%s" is not a valid prefix.)", ERROR_COMMON_PREFIX, p_prefix));
 	}
 
 	Ref<DirAccess> dir_access = DirAccess::open(OS::get_singleton()->get_temp_path());
@@ -351,7 +351,7 @@ Ref<DirAccess> 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<FileAccess>(), vformat(R"(%s: "%s" couldn't create directory "%s".)", ERROR_COMMON_PREFIX, path));
+		ERR_FAIL_V_MSG(Ref<DirAccess>(), vformat(R"(%s: "%s" couldn't create directory "%s".)", ERROR_COMMON_PREFIX, path));
 	}
 	err = dir_access->change_dir(path);
 	if (err != OK) {

+ 30 - 23
core/object/object.h

@@ -830,16 +830,27 @@ public:
 	void detach_from_objectdb();
 	_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
 
-	template <typename T>
-	static T *cast_to(Object *p_object) {
+	template <typename T, typename O>
+	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<T>() ? static_cast<T *>(p_object) : nullptr;
+		return p_object && p_object->template derives_from<T, O>() ? static_cast<T *>(p_object) : nullptr;
+	}
+
+	template <typename T, typename O>
+	static const T *cast_to(const O *p_object) {
+		return p_object && p_object->template derives_from<T, O>() ? static_cast<const T *>(p_object) : nullptr;
+	}
+
+	// cast_to versions for types that implicitly convert to Object.
+	template <typename T>
+	static T *cast_to(Object *p_object) {
+		return p_object && p_object->template derives_from<T, Object>() ? static_cast<T *>(p_object) : nullptr;
 	}
 
 	template <typename T>
 	static const T *cast_to(const Object *p_object) {
-		return p_object && p_object->derives_from<T>() ? static_cast<const T *>(p_object) : nullptr;
+		return p_object && p_object->template derives_from<T, Object>() ? static_cast<const T *>(p_object) : nullptr;
 	}
 
 	enum {
@@ -872,7 +883,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 <typename T>
+	template <typename T, typename O>
 	bool derives_from() const;
 
 	const StringName &get_class_name() const;
@@ -1041,27 +1052,23 @@ public:
 bool predelete_handler(Object *p_object);
 void postinitialize_handler(Object *p_object);
 
-template <typename T>
+template <typename T, typename O>
 bool Object::derives_from() const {
-	static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object.");
-	static_assert(std::is_same_v<std::decay_t<T>, 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<T, O>) {
+		// 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<Object, O>, "derives_from can only be used with Object subclasses.");
+		static_assert(std::is_base_of_v<O, T>, "Cannot cast argument to T because T does not derive from the argument's known class.");
+		static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS.");
 
-template <>
-inline bool Object::derives_from<Object>() const {
-	return true;
-}
-
-template <>
-inline bool Object::derives_from<const Object>() const {
-	return true;
+		// 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());
+		}
+	}
 }
 
 class ObjectDB {

+ 1 - 1
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<EditorExportPlugin>());
+		export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>());
 	}
 }
 

+ 3 - 1
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> 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) {

+ 2 - 2
editor/inspector/editor_preview_plugins.cpp

@@ -192,7 +192,7 @@ Ref<Texture2D> EditorImagePreviewPlugin::generate(const Ref<Resource> &p_from, c
 	Ref<Image> img = p_from;
 
 	if (img.is_null() || img->is_empty()) {
-		return Ref<Image>();
+		return Ref<Texture2D>();
 	}
 
 	img = img->duplicate();
@@ -200,7 +200,7 @@ Ref<Texture2D> EditorImagePreviewPlugin::generate(const Ref<Resource> &p_from, c
 
 	if (img->is_compressed()) {
 		if (img->decompress() != OK) {
-			return Ref<Image>();
+			return Ref<Texture2D>();
 		}
 	} else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) {
 		img->convert(Image::FORMAT_RGBA8);

+ 1 - 1
editor/scene/3d/node_3d_editor_plugin.cpp

@@ -514,7 +514,7 @@ void ViewportRotationControl::gui_input(const Ref<InputEvent> &p_event) {
 
 	const Ref<InputEventScreenDrag> 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());
 	}
 }
 

+ 0 - 20
modules/gltf/gltf_document.cpp

@@ -2143,10 +2143,6 @@ Dictionary GLTFDocument::_serialize_image(Ref<GLTFState> p_state, Ref<Image> p_i
 		bv->byte_offset = p_state->buffers[bi].size();
 
 		Vector<uint8_t> buffer;
-		Ref<ImageTexture> 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<GLTFState> p_state) {
 					height = ao_texture->get_height();
 					width = ao_texture->get_width();
 					ao_image = ao_texture->get_image();
-					Ref<ImageTexture> 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<GLTFState> p_state) {
 					height = roughness_texture->get_height();
 					width = roughness_texture->get_width();
 					roughness_image = roughness_texture->get_image();
-					Ref<ImageTexture> 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<GLTFState> p_state) {
 					height = metallic_texture->get_height();
 					width = metallic_texture->get_width();
 					metallness_image = metallic_texture->get_image();
-					Ref<ImageTexture> 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<GLTFState> p_state) {
 					// Code for uncompressing RG normal maps
 					Ref<Image> img = normal_texture->get_image();
 					if (img.is_valid()) {
-						Ref<ImageTexture> 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++) {

+ 1 - 1
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);