2
0
Эх сурвалжийг харах

Mono: Fail on script instance creation if constructor was not found

Previously this would result in NULL dereferencing. Now we fail with an error.
Ignacio Etcheverry 6 жил өмнө
parent
commit
22b41ab2fe

+ 30 - 3
modules/mono/csharp_script.cpp

@@ -1528,6 +1528,15 @@ MonoObject *CSharpInstance::_internal_new_managed() {
 	CRASH_COND(!gchandle.is_valid());
 #endif
 
+	// Search the constructor first, to fail with an error if it's not found before allocating anything else.
+	GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
+	if (ctor == NULL) {
+		ERR_PRINTS("Cannot create script instance because the class does not define a default constructor: " + script->get_path());
+
+		ERR_EXPLAIN("Constructor not found");
+		ERR_FAIL_V(NULL);
+	}
+
 	CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
 
 	ERR_FAIL_NULL_V(owner, NULL);
@@ -1557,7 +1566,6 @@ MonoObject *CSharpInstance::_internal_new_managed() {
 	CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
 
 	// Construct
-	GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
 	ctor->invoke_raw(mono_object, NULL);
 
 	return mono_object;
@@ -1900,13 +1908,21 @@ bool CSharpScript::_update_exports() {
 		MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
 
 		if (!tmp_object) {
-			ERR_PRINT("Failed to create temporary MonoObject");
+			ERR_PRINT("Failed to allocate temporary MonoObject");
 			return false;
 		}
 
 		uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
 
 		GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
+
+		if (ctor == NULL) {
+			ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a default constructor: " + get_path());
+
+			ERR_EXPLAIN("Constructor not found");
+			ERR_FAIL_V(NULL);
+		}
+
 		MonoException *ctor_exc = NULL;
 		ctor->invoke(tmp_object, NULL, &ctor_exc);
 
@@ -2387,6 +2403,18 @@ StringName CSharpScript::get_instance_base_type() const {
 CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
 
 	/* STEP 1, CREATE */
+
+	// Search the constructor first, to fail with an error if it's not found before allocating anything else.
+	GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
+	if (ctor == NULL) {
+		if (p_argcount == 0) {
+			ERR_PRINTS("Cannot create script instance because the class does not define a default constructor: " + get_path());
+		}
+
+		ERR_EXPLAIN("Constructor not found");
+		ERR_FAIL_V(NULL);
+	}
+
 	Ref<Reference> ref;
 	if (p_isref) {
 		// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
@@ -2453,7 +2481,6 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
 	CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
 
 	// Construct
-	GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
 	ctor->invoke(mono_object, p_args);
 
 	/* STEP 3, PARTY */