Procházet zdrojové kódy

C#: Fix some crashes during assemblies reloading

Ignacio Etcheverry před 6 roky
rodič
revize
dd22cc7527
2 změnil soubory, kde provedl 42 přidání a 33 odebrání
  1. 41 33
      modules/mono/csharp_script.cpp
  2. 1 0
      modules/mono/csharp_script.h

+ 41 - 33
modules/mono/csharp_script.cpp

@@ -867,6 +867,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 
 			script->reload(p_soft_reload);
 			script->update_exports();
+
+			if (!script->valid) {
+				script->pending_reload_instances.clear();
+				continue;
+			}
 		} else {
 			const StringName &class_namespace = script->tied_class_namespace_for_reload;
 			const StringName &class_name = script->tied_class_name_for_reload;
@@ -897,12 +902,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 
 			GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class);
 
-			Ref<CSharpScript> new_script = CSharpScript::create_for_managed_type(script_class, native);
-			CRASH_COND(new_script.is_null());
-
-			new_script->pending_reload_instances = script->pending_reload_instances;
-			new_script->pending_reload_state = script->pending_reload_state;
-			script = new_script;
+			CSharpScript::initialize_for_managed_type(script, script_class, native);
 		}
 
 		String native_name = NATIVE_GDMONOCLASS_NAME(script->native);
@@ -953,7 +953,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 				CRASH_COND(si != NULL);
 #endif
 				// Re-create script instance
-
 				obj->set_script(script.get_ref_ptr()); // will create the script instance as well
 			}
 		}
@@ -2673,35 +2672,46 @@ void CSharpScript::_bind_methods() {
 
 Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
 
-	// This method should not fail
+	// This method should not fail, only assertions allowed
 
 	CRASH_COND(p_class == NULL);
 
 	// TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
 	Ref<CSharpScript> script = memnew(CSharpScript);
 
-	script->name = p_class->get_name();
-	script->script_class = p_class;
-	script->native = p_native;
+	initialize_for_managed_type(script, p_class, p_native);
+
+	return script;
+}
+
+void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native) {
+
+	// This method should not fail, only assertions allowed
+
+	CRASH_COND(p_class == NULL);
+
+	p_script->name = p_class->get_name();
+	p_script->script_class = p_class;
+	p_script->native = p_native;
 
-	CRASH_COND(script->native == NULL);
+	CRASH_COND(p_script->native == NULL);
 
-	GDMonoClass *base = script->script_class->get_parent_class();
+	GDMonoClass *base = p_script->script_class->get_parent_class();
 
-	if (base != script->native)
-		script->base = base;
+	if (base != p_script->native)
+		p_script->base = base;
 
-	script->valid = true;
-	script->tool = script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
+	p_script->valid = true;
+	p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
 
-	if (!script->tool) {
-		GDMonoClass *nesting_class = script->script_class->get_nesting_class();
-		script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
+	if (!p_script->tool) {
+		GDMonoClass *nesting_class = p_script->script_class->get_nesting_class();
+		p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
 	}
 
 #if TOOLS_ENABLED
-	if (!script->tool) {
-		script->tool = script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
+	if (!p_script->tool) {
+		p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
 	}
 #endif
 
@@ -2710,10 +2720,10 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD
 	// Native base methods must be fetched before the current class.
 	// Not needed if the script class itself is a native class.
 
-	if (script->script_class != script->native) {
-		GDMonoClass *native_top = script->native;
+	if (p_script->script_class != p_script->native) {
+		GDMonoClass *native_top = p_script->native;
 		while (native_top) {
-			native_top->fetch_methods_with_godot_api_checks(script->native);
+			native_top->fetch_methods_with_godot_api_checks(p_script->native);
 
 			if (native_top == CACHED_CLASS(GodotObject))
 				break;
@@ -2723,19 +2733,17 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD
 	}
 #endif
 
-	script->script_class->fetch_methods_with_godot_api_checks(script->native);
+	p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
 
 	// Need to fetch method from base classes as well
-	GDMonoClass *top = script->script_class;
-	while (top && top != script->native) {
-		top->fetch_methods_with_godot_api_checks(script->native);
+	GDMonoClass *top = p_script->script_class;
+	while (top && top != p_script->native) {
+		top->fetch_methods_with_godot_api_checks(p_script->native);
 		top = top->get_parent_class();
 	}
 
-	script->load_script_signals(script->script_class, script->native);
-	script->_update_member_info_no_exports();
-
-	return script;
+	p_script->load_script_signals(p_script->script_class, p_script->native);
+	p_script->_update_member_info_no_exports();
 }
 
 bool CSharpScript::can_instance() const {

+ 1 - 0
modules/mono/csharp_script.h

@@ -144,6 +144,7 @@ class CSharpScript : public Script {
 	// Do not use unless you know what you are doing
 	friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
 	static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
+	static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
 
 protected:
 	static void _bind_methods();