X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-error.c;h=55f84ffd8e8f1de87aab2c64464ebab9d3955ea6;hb=8e6f129087207e14b5bc411554229441a7b522e6;hp=94c0c4fd35a29639b9d692e08a9d7ce32d4ffbe8;hpb=ef0ddf45c3081e799edcb4e95770186514b80cf1;p=mono.git diff --git a/mono/utils/mono-error.c b/mono/utils/mono-error.c index 94c0c4fd35a..55f84ffd8e8 100644 --- a/mono/utils/mono-error.c +++ b/mono/utils/mono-error.c @@ -8,13 +8,13 @@ */ #include +#include #include "mono-error.h" #include "mono-error-internals.h" #include -#include +#include #include -#include #include #define set_error_messagev() do { \ @@ -38,9 +38,17 @@ is_managed_exception (MonoErrorInternal *error) return (error->error_code == MONO_ERROR_EXCEPTION_INSTANCE); } +static gboolean +is_boxed (MonoErrorInternal *error) +{ + return ((error->flags & MONO_ERROR_MEMPOOL_BOXED) != 0); +} + static void mono_error_prepare (MonoErrorInternal *error) { + /* mono_error_set_* after a mono_error_cleanup without an intervening init */ + g_assert (error->error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL); if (error->error_code != MONO_ERROR_NONE) return; @@ -91,6 +99,13 @@ mono_error_init_flags (MonoError *oerror, unsigned short flags) error->flags = flags; } +/** + * mono_error_init: + * @error: Pointer to MonoError struct to initialize + * + * Any function which takes a MonoError for purposes of reporting an error + * is required to call either this or mono_error_init_flags on entry. + */ void mono_error_init (MonoError *error) { @@ -101,15 +116,32 @@ void mono_error_cleanup (MonoError *oerror) { MonoErrorInternal *error = (MonoErrorInternal*)oerror; - if (error->error_code == MONO_ERROR_NONE) + short int orig_error_code = error->error_code; + gboolean free_strings = error->flags & MONO_ERROR_FREE_STRINGS; + gboolean has_instance_handle = is_managed_exception (error); + + /* Two cleanups in a row without an intervening init. */ + g_assert (orig_error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL); + /* Mempool stored error shouldn't be cleaned up */ + g_assert (!is_boxed (error)); + + /* Mark it as cleaned up. */ + error->error_code = MONO_ERROR_CLEANUP_CALLED_SENTINEL; + error->flags = 0; + + if (orig_error_code == MONO_ERROR_NONE) return; - if (is_managed_exception (error)) + + if (has_instance_handle) 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 + error->full_message = NULL; + error->full_message_with_fields = NULL; + if (!free_strings) //no memory was allocated return; g_free ((char*)error->type_name); @@ -118,6 +150,9 @@ mono_error_cleanup (MonoError *oerror) g_free ((char*)error->exception_name_space); g_free ((char*)error->exception_name); g_free ((char*)error->first_argument); + error->type_name = error->assembly_name = error->member_name = error->exception_name_space = error->exception_name = error->first_argument = NULL; + error->exn.klass = NULL; + } gboolean @@ -262,18 +297,27 @@ mono_error_set_assembly_load_simple (MonoError *oerror, const char *assembly_nam if (refection_only) mono_error_set_assembly_load (oerror, assembly_name, "Cannot resolve dependency to assembly because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event."); else - mono_error_set_assembly_load (oerror, assembly_name, "Could not load file or assembly or one of its dependencies."); + mono_error_set_assembly_load (oerror, assembly_name, "Could not load file or assembly '%s' or one of its dependencies.", assembly_name); } void mono_error_set_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, ...) +{ + va_list args; + va_start (args, msg_format); + mono_error_vset_type_load_class (oerror, klass, msg_format, args); + va_end (args); +} + +void +mono_error_vset_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, va_list args) { MonoErrorInternal *error = (MonoErrorInternal*)oerror; mono_error_prepare (error); error->error_code = MONO_ERROR_TYPE_LOAD; mono_error_set_class (oerror, klass); - set_error_message (); + set_error_messagev (); } /* @@ -388,7 +432,7 @@ mono_error_set_execution_engine (MonoError *oerror, const char *msg_format, ...) } /** - * mono_error_set_execution_engine: + * mono_error_set_not_supported: * * System.NotSupportedException */ @@ -401,120 +445,49 @@ mono_error_set_not_supported (MonoError *oerror, const char *msg_format, ...) va_end (args); } +/** + * mono_error_set_invalid_operation: + * + * System.InvalidOperationException + */ void -mono_error_set_exception_instance (MonoError *oerror, MonoException *exc) +mono_error_set_invalid_operation (MonoError *oerror, const char *msg_format, ...) { - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - - mono_error_prepare (error); - error->error_code = MONO_ERROR_EXCEPTION_INSTANCE; - error->exn.instance_handle = mono_gchandle_new (exc ? &exc->object : NULL, FALSE); + va_list args; + va_start (args, msg_format); + mono_error_set_generic_errorv (oerror, "System", "InvalidOperationException", msg_format, args); + va_end (args); } void -mono_error_set_from_loader_error (MonoError *oerror) +mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...) { - MonoLoaderError *loader_error = mono_loader_get_last_error (); MonoErrorInternal *error = (MonoErrorInternal*)oerror; - gboolean dup_strings = TRUE; mono_error_prepare (error); + error->error_code = MONO_ERROR_INVALID_PROGRAM; - if (!loader_error) { - mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from an empty loader-error"); - return; - } - - switch (loader_error->exception_type) { - case MONO_EXCEPTION_NONE: - mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from a non-error loader-error"); - break; - - case MONO_EXCEPTION_INVALID_PROGRAM: - mono_error_set_generic_error (oerror, "System", "InvalidProgramException", "Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_UNVERIFIABLE_IL: - mono_error_set_generic_error (oerror, "System.Security", "VerificationException", "Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_MISSING_METHOD: - error->error_code = MONO_ERROR_MISSING_METHOD; - mono_error_set_type_name (oerror, loader_error->class_name); - mono_error_set_member_name (oerror, loader_error->member_name); - error->full_message = g_strdup ("Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_MISSING_FIELD: - mono_error_set_field_load (oerror, loader_error->klass, loader_error->member_name, "Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_TYPE_LOAD: - mono_error_set_type_load_name (oerror, g_strdup (loader_error->class_name), g_strdup (loader_error->assembly_name), "Failed for unknown reasons."); - dup_strings = FALSE; - break; - - case MONO_EXCEPTION_FILE_NOT_FOUND: - mono_error_set_assembly_load_simple (oerror, loader_error->assembly_name, loader_error->ref_only); - break; - - case MONO_EXCEPTION_METHOD_ACCESS: - mono_error_set_generic_error (oerror, "System", "MethodAccessException", "Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_FIELD_ACCESS: - mono_error_set_generic_error (oerror, "System", "FieldAccessException", "Failed for unknown reasons."); - break; - - case MONO_EXCEPTION_OBJECT_SUPPLIED: - case MONO_EXCEPTION_GENERIC_SHARING_FAILED: - mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from JIT internal error %d", loader_error->exception_type); - break; - - case MONO_EXCEPTION_BAD_IMAGE: - mono_error_set_bad_image_name (oerror, "", "%s", loader_error->msg); - break; - - case MONO_EXCEPTION_OUT_OF_MEMORY: - mono_error_set_out_of_memory (oerror, "Failed for unknown reasons."); - break; + set_error_message (); +} - default: - mono_error_set_execution_engine (oerror, "Runtime tried to produce an unknown loader-error %d", loader_error->exception_type); - break; - } +void +mono_error_set_exception_instance (MonoError *oerror, MonoException *exc) +{ + MonoErrorInternal *error = (MonoErrorInternal*)oerror; - mono_error_dup_strings (oerror, dup_strings); - mono_loader_clear_error (); + mono_error_prepare (error); + error->error_code = MONO_ERROR_EXCEPTION_INSTANCE; + error->exn.instance_handle = mono_gchandle_new (exc ? &exc->object : NULL, FALSE); } void -mono_loader_set_error_from_mono_error (MonoError *oerror) +mono_error_set_exception_handle (MonoError *oerror, MonoExceptionHandle exc) { MonoErrorInternal *error = (MonoErrorInternal*)oerror; - switch (error->error_code) { - case MONO_ERROR_MISSING_METHOD: - 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->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)); - break; - case MONO_ERROR_FILE_NOT_FOUND: - /* XXX can't recover if it's ref only or not */ - mono_loader_set_error_assembly_load (get_assembly_name (error), FALSE); - break; - 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)); - } + mono_error_prepare (error); + error->error_code = MONO_ERROR_EXCEPTION_INSTANCE; + error->exn.instance_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST(MonoObject, exc), FALSE); } void @@ -629,7 +602,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) break; } - exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "MissingMethodException", type_name, method_name); + exception = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "MissingMethodException", type_name, method_name, error_out); if (exception) set_message_on_exception (exception, error, error_out); } else { @@ -649,7 +622,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) break; } - exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "MissingFieldException", type_name, field_name); + exception = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "MissingFieldException", type_name, field_name, error_out); if (exception) set_message_on_exception (exception, error, error_out); } else { @@ -671,8 +644,8 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) } } - exception = mono_exception_from_name_two_strings (mono_get_corlib (), "System", "TypeLoadException", type_name, assembly_name); - if (exception) + exception = mono_exception_from_name_two_strings_checked (mono_get_corlib (), "System", "TypeLoadException", type_name, assembly_name, error_out); + if (exception && error->full_message != NULL && strcmp (error->full_message, "")) set_message_on_exception (exception, error, error_out); } else { exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", error->full_message); @@ -697,9 +670,9 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) } if (error->error_code == MONO_ERROR_FILE_NOT_FOUND) - exception = mono_exception_from_name_two_strings (mono_get_corlib (), "System.IO", "FileNotFoundException", msg, assembly_name); + exception = mono_exception_from_name_two_strings_checked (mono_get_corlib (), "System.IO", "FileNotFoundException", msg, assembly_name, error_out); else - exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "BadImageFormatException", msg, assembly_name); + exception = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "BadImageFormatException", msg, assembly_name, error_out); } else { if (error->error_code == MONO_ERROR_FILE_NOT_FOUND) exception = mono_exception_from_name_msg (mono_get_corlib (), "System.IO", "FileNotFoundException", error->full_message); @@ -751,6 +724,17 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) exception = (MonoException*) mono_gchandle_get_target (error->exn.instance_handle); break; + case MONO_ERROR_CLEANUP_CALLED_SENTINEL: + mono_error_set_execution_engine (error_out, "MonoError reused after mono_error_cleanup"); + break; + + case MONO_ERROR_INVALID_PROGRAM: { + gboolean lacks_message = error->flags & MONO_ERROR_INCOMPLETE; + if (lacks_message) + return mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", ""); + else + return mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", error->full_message); + } default: mono_error_set_execution_engine (error_out, "Invalid error-code %d", error->error_code); } @@ -773,6 +757,9 @@ mono_error_convert_to_exception (MonoError *target_error) MonoError error; MonoException *ex; + /* Mempool stored error shouldn't be cleaned up */ + g_assert (!is_boxed ((MonoErrorInternal*)target_error)); + if (mono_error_ok (target_error)) return NULL; @@ -795,3 +782,97 @@ mono_error_move (MonoError *dest, MonoError *src) memcpy (dest, src, sizeof (MonoErrorInternal)); mono_error_init (src); } + +/** + * mono_error_box: + * @ierror: The input error that will be boxed. + * @image: The mempool of this image will hold the boxed error. + * + * Creates a new boxed error in the given mempool from MonoError. + * It does not alter ierror, so you still have to clean it up with + * mono_error_cleanup or mono_error_convert_to_exception or another such function. + * + * Returns the boxed error, or NULL if the mempool could not allocate. + */ +MonoErrorBoxed* +mono_error_box (const MonoError *ierror, MonoImage *image) +{ + MonoErrorInternal *from = (MonoErrorInternal*)ierror; + /* Don't know how to box a gchandle */ + g_assert (!is_managed_exception (from)); + MonoErrorBoxed* box = mono_image_alloc (image, sizeof (MonoErrorBoxed)); + box->image = image; + mono_error_init_flags (&box->error, MONO_ERROR_MEMPOOL_BOXED); + MonoErrorInternal *to = (MonoErrorInternal*)&box->error; + +#define DUP_STR(field) do { \ + if (from->field) { \ + if (!(to->field = mono_image_strdup (image, from->field))) \ + to->flags |= MONO_ERROR_INCOMPLETE; \ + } else { \ + to->field = NULL; \ + } \ + } while (0) + + to->error_code = from->error_code; + DUP_STR (type_name); + DUP_STR (assembly_name); + DUP_STR (member_name); + DUP_STR (exception_name_space); + DUP_STR (exception_name); + DUP_STR (full_message); + DUP_STR (full_message_with_fields); + DUP_STR (first_argument); + to->exn.klass = from->exn.klass; + +#undef DUP_STR + + return box; +} + + +/** + * mono_error_set_from_boxed: + * @oerror: The error that will be set to the contents of the box. + * @box: A mempool-allocated error. + * + * Sets the error condition in the oerror from the contents of the + * given boxed error. Does not alter the boxed error, so it can be + * used in a future call to mono_error_set_from_boxed as needed. The + * oerror should've been previously initialized with mono_error_init, + * as usual. + * + * Returns TRUE on success or FALSE on failure. + */ +gboolean +mono_error_set_from_boxed (MonoError *oerror, const MonoErrorBoxed *box) +{ + MonoErrorInternal* to = (MonoErrorInternal*)oerror; + MonoErrorInternal* from = (MonoErrorInternal*)&box->error; + g_assert (!is_managed_exception (from)); + + mono_error_prepare (to); + to->flags |= MONO_ERROR_FREE_STRINGS; +#define DUP_STR(field) do { \ + if (from->field) { \ + if (!(to->field = g_strdup (from->field))) \ + to->flags |= MONO_ERROR_INCOMPLETE; \ + } else { \ + to->field = NULL; \ + } \ + } while (0) + + to->error_code = from->error_code; + DUP_STR (type_name); + DUP_STR (assembly_name); + DUP_STR (member_name); + DUP_STR (exception_name_space); + DUP_STR (exception_name); + DUP_STR (full_message); + DUP_STR (full_message_with_fields); + DUP_STR (first_argument); + to->exn.klass = from->exn.klass; + +#undef DUP_STR + return (to->flags & MONO_ERROR_INCOMPLETE) == 0 ; +}