diff options
author | monojenkins <jo.shields+jenkins@xamarin.com> | 2016-01-26 22:15:17 +0300 |
---|---|---|
committer | monojenkins <jo.shields+jenkins@xamarin.com> | 2016-01-26 22:15:17 +0300 |
commit | 0658b3879aaa68b0b1124a56da4845c131fe10b4 (patch) | |
tree | 16f1aafc5445f4f41e65bb7652c2e85687af4418 | |
parent | 1a2b21803c38f3aeabb6cceef2a0be0309123b66 (diff) | |
parent | 305bfbae4ce3b4b616879578f390f9f540dbe38f (diff) |
Merge pull request #2516 from lambdageek/monoerror-exception_instance
[runtime] Add MONO_ERROR_EXCEPTION_INSTANCE MonoError
This kind of MonoError can encapsulate a managed MonoException
object. (For example as a result of mono_runtime_invoke ()).
Issues:
- [x] Memory leak correctness.
`MonoError` already leaks memory if you simply swallow it without calling `mono_error_cleanup` or some function that calls it (for example `mono_error_raise_exception` or `mono_error_convert_to_exception`).
Now if we have an encapsulated exception, we'll leak a GC handle unless cleanup happens.
-rw-r--r-- | mono/utils/mono-error-internals.h | 14 | ||||
-rw-r--r-- | mono/utils/mono-error.c | 76 | ||||
-rw-r--r-- | mono/utils/mono-error.h | 4 |
3 files changed, 76 insertions, 18 deletions
diff --git a/mono/utils/mono-error-internals.h b/mono/utils/mono-error-internals.h index 774203d343c..926e76c9bbd 100644 --- a/mono/utils/mono-error-internals.h +++ b/mono/utils/mono-error-internals.h @@ -15,7 +15,16 @@ typedef struct { const char *member_name; const char *exception_name_space; const char *exception_name; - MonoClass *klass; + union { + /* Valid if error_code != MONO_ERROR_EXCEPTION_INSTANCE. + * Used by type or field load errors and generic error specified by class. + */ + MonoClass *klass; + /* Valid if error_code == MONO_ERROR_EXCEPTION_INSTANCE. + * Generic error specified by a managed instance. + */ + uint32_t instance_handle; + } exn; const char *full_message; const char *full_message_with_fields; const char *first_argument; @@ -77,6 +86,9 @@ void mono_error_set_generic_error (MonoError *error, const char * name_space, const char *name, const char *msg_format, ...); void +mono_error_set_exception_instance (MonoError *error, MonoException *exc); + +void mono_error_set_from_loader_error (MonoError *error); MonoException* diff --git a/mono/utils/mono-error.c b/mono/utils/mono-error.c index 4ac7d6766ef..ca3350c5fd4 100644 --- a/mono/utils/mono-error.c +++ b/mono/utils/mono-error.c @@ -13,6 +13,8 @@ #include <mono/metadata/exception.h> #include <mono/metadata/class-internals.h> #include <mono/metadata/debug-helpers.h> +#include <mono/metadata/object.h> +#include <mono/metadata/object-internals.h> #define set_error_message() do { \ va_list args; \ @@ -22,6 +24,12 @@ va_end (args); \ } while (0) +static gboolean +is_managed_exception (MonoErrorInternal *error) +{ + return (error->error_code == MONO_ERROR_EXCEPTION_INSTANCE); +} + static void mono_error_prepare (MonoErrorInternal *error) { @@ -29,7 +37,18 @@ mono_error_prepare (MonoErrorInternal *error) return; error->type_name = error->assembly_name = error->member_name = error->full_message = error->exception_name_space = error->exception_name = error->full_message_with_fields = error->first_argument = NULL; - error->klass = NULL; + error->exn.klass = NULL; +} + +static MonoClass* +get_class (MonoErrorInternal *error) +{ + MonoClass *klass = NULL; + if (is_managed_exception (error)) + klass = mono_object_class (mono_gchandle_get_target (error->exn.instance_handle)); + else + klass = error->exn.klass; + return klass; } static const char* @@ -37,8 +56,9 @@ get_type_name (MonoErrorInternal *error) { if (error->type_name) return error->type_name; - if (error->klass) - return error->klass->name; + MonoClass *klass = get_class (error); + if (klass) + return klass->name; return "<unknown type>"; } @@ -47,8 +67,9 @@ get_assembly_name (MonoErrorInternal *error) { if (error->assembly_name) return error->assembly_name; - if (error->klass && error->klass->image) - return error->klass->image->name; + MonoClass *klass = get_class (error); + if (klass && klass->image) + return klass->image->name; return "<unknown assembly>"; } @@ -75,6 +96,9 @@ mono_error_cleanup (MonoError *oerror) if (error->error_code == MONO_ERROR_NONE) return; + if (is_managed_exception (error)) + mono_gchandle_free (error->exn.instance_handle); + g_free ((char*)error->full_message); g_free ((char*)error->full_message_with_fields); if (!(error->flags & MONO_ERROR_FREE_STRINGS)) //no memory was allocated @@ -196,7 +220,9 @@ mono_error_set_class (MonoError *oerror, MonoClass *klass) { MonoErrorInternal *error = (MonoErrorInternal*)oerror; - error->klass = klass; + if (is_managed_exception (error)) + return; + error->exn.klass = klass; } static void @@ -317,6 +343,15 @@ mono_error_set_generic_error (MonoError *oerror, const char * name_space, const } void +mono_error_set_exception_instance (MonoError *oerror, MonoException *exc) +{ + MonoErrorInternal *error = (MonoErrorInternal*)oerror; + + error->error_code = MONO_ERROR_EXCEPTION_INSTANCE; + error->exn.instance_handle = mono_gchandle_new (exc ? &exc->object : NULL, FALSE); +} + +void mono_error_set_from_loader_error (MonoError *oerror) { MonoLoaderError *loader_error = mono_loader_get_last_error (); @@ -403,7 +438,7 @@ mono_loader_set_error_from_mono_error (MonoError *oerror) mono_loader_set_error_method_load (get_type_name (error), error->member_name); break; case MONO_ERROR_MISSING_FIELD: - mono_loader_set_error_field_load (error->klass, error->member_name); + mono_loader_set_error_field_load (error->exn.klass, error->member_name); break; case MONO_ERROR_TYPE_LOAD: mono_loader_set_error_type_load (get_type_name (error), get_assembly_name (error)); @@ -415,6 +450,8 @@ mono_loader_set_error_from_mono_error (MonoError *oerror) case MONO_ERROR_BAD_IMAGE: mono_loader_set_error_bad_image (g_strdup (error->full_message)); break; + case MONO_ERROR_EXCEPTION_INSTANCE: + mono_loader_set_error_bad_image (g_strdup_printf ("Non translatable error")); default: mono_loader_set_error_bad_image (g_strdup_printf ("Non translatable error: %s", error->full_message)); } @@ -467,11 +504,14 @@ get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, Mono if (error->type_name) { res = mono_string_new (domain, error->type_name); - } else if (error->klass) { - char *name = mono_type_full_name (&error->klass->byval_arg); - if (name) { - res = mono_string_new (domain, name); - g_free (name); + } else { + MonoClass *klass = get_class (error); + if (klass) { + char *name = mono_type_full_name (&klass->byval_arg); + if (name) { + res = mono_string_new (domain, name); + g_free (name); + } } } if (!res) @@ -506,7 +546,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) return NULL; case MONO_ERROR_MISSING_METHOD: - if ((error->type_name || error->klass) && error->member_name) { + if ((error->type_name || error->exn.klass) && error->member_name) { type_name = get_type_name_as_mono_string (error, domain, error_out); if (!mono_error_ok (error_out)) break; @@ -526,7 +566,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) break; case MONO_ERROR_MISSING_FIELD: - if ((error->type_name || error->klass) && error->member_name) { + if ((error->type_name || error->exn.klass) && error->member_name) { type_name = get_type_name_as_mono_string (error, domain, error_out); if (!mono_error_ok (error_out)) break; @@ -606,8 +646,8 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) case MONO_ERROR_NOT_VERIFIABLE: { char *type_name = NULL, *message; - if (error->klass) { - type_name = mono_type_get_full_name (error->klass); + if (error->exn.klass) { + type_name = mono_type_get_full_name (error->exn.klass); if (!type_name) { mono_error_set_out_of_memory (error_out, "Could not allocate message"); break; @@ -631,6 +671,10 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) exception = mono_exception_from_name_msg (mono_defaults.corlib, error->exception_name_space, error->exception_name, error->full_message); break; + case MONO_ERROR_EXCEPTION_INSTANCE: + exception = (MonoException*) mono_gchandle_get_target (error->exn.instance_handle); + break; + default: mono_error_set_generic_error (error_out, "System", "ExecutionEngineException", "Invalid error-code %d", error->error_code); } diff --git a/mono/utils/mono-error.h b/mono/utils/mono-error.h index 12747711fc4..58a401c13ec 100644 --- a/mono/utils/mono-error.h +++ b/mono/utils/mono-error.h @@ -29,7 +29,9 @@ enum { * This is a generic error mechanism is you need to raise an arbitrary corlib exception. * You must pass the exception name otherwise prepare_exception will fail with internal execution. */ - MONO_ERROR_GENERIC = 9 + MONO_ERROR_GENERIC = 9, + /* This one encapsulates a managed exception instance */ + MONO_ERROR_EXCEPTION_INSTANCE = 10 }; /*Keep in sync with MonoErrorInternal*/ |