X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-error.c;h=27f2b62fb248ff784d2f6dbc9b350f98a7613d07;hb=56b3c007f428d93b7f230d58744393ad69e4ca63;hp=7e186b6b717ce06b2f4103bb2ab3abe22e5ce2df;hpb=7b20c1b85105883fe0279403cd31ff5882435a06;p=mono.git diff --git a/mono/utils/mono-error.c b/mono/utils/mono-error.c index 7e186b6b717..27f2b62fb24 100644 --- a/mono/utils/mono-error.c +++ b/mono/utils/mono-error.c @@ -1,5 +1,6 @@ -/* - * mono-error.c: Error handling code +/** + * \file + * Error handling code * * Authors: * Rodrigo Kumpera (rkumpera@novell.com) @@ -38,6 +39,12 @@ 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) { @@ -95,10 +102,9 @@ mono_error_init_flags (MonoError *oerror, unsigned short 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. + * \param error Pointer to \c MonoError struct to initialize + * Any function which takes a \c MonoError for purposes of reporting an error + * is required to call either this or \c mono_error_init_flags on entry. */ void mono_error_init (MonoError *error) @@ -116,6 +122,8 @@ mono_error_cleanup (MonoError *oerror) /* 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; @@ -168,6 +176,17 @@ mono_error_get_error_code (MonoError *error) return error->error_code; } +const char* +mono_error_get_exception_name (MonoError *oerror) +{ + MonoErrorInternal *error = (MonoErrorInternal*)oerror; + + if (error->error_code == MONO_ERROR_NONE) + return NULL; + + return error->exception_name; +} + /*Return a pointer to the internal error message, might be NULL. Caller should not release it.*/ const char* @@ -289,18 +308,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 (); } /* @@ -442,6 +470,20 @@ mono_error_set_invalid_operation (MonoError *oerror, const char *msg_format, ... va_end (args); } +/** + * mono_error_set_file_not_found: + * + * System.IO.FileNotFoundException + */ +void +mono_error_set_file_not_found (MonoError *oerror, const char *msg_format, ...) +{ + va_list args; + va_start (args, msg_format); + mono_error_set_generic_errorv (oerror, "System.IO", "FileNotFoundException", msg_format, args); + va_end (args); +} + void mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...) { @@ -453,6 +495,17 @@ mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...) set_error_message (); } +/** + * mono_error_set_invalid_cast: + * + * System.InvalidCastException + */ +void +mono_error_set_invalid_cast (MonoError *oerror) +{ + mono_error_set_generic_error (oerror, "System", "InvalidCastException", ""); +} + void mono_error_set_exception_instance (MonoError *oerror, MonoException *exc) { @@ -463,6 +516,16 @@ mono_error_set_exception_instance (MonoError *oerror, MonoException *exc) error->exn.instance_handle = mono_gchandle_new (exc ? &exc->object : NULL, FALSE); } +void +mono_error_set_exception_handle (MonoError *oerror, MonoExceptionHandle exc) +{ + MonoErrorInternal *error = (MonoErrorInternal*)oerror; + + 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 mono_error_set_out_of_memory (MonoError *oerror, const char *msg_format, ...) { @@ -514,20 +577,30 @@ mono_error_set_not_verifiable (MonoError *oerror, MonoMethod *method, const char } +/* Used by mono_error_prepare_exception - it sets its own error on mono_string_new_checked failure. */ +static MonoString* +string_new_cleanup (MonoDomain *domain, const char *text) +{ + MonoError ignored_err; + MonoString *result = mono_string_new_checked (domain, text, &ignored_err); + mono_error_cleanup (&ignored_err); + return result; +} + static MonoString* get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, MonoError *error_out) { MonoString* res = NULL; if (error->type_name) { - res = mono_string_new (domain, error->type_name); + res = string_new_cleanup (domain, error->type_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); + res = string_new_cleanup (domain, name); g_free (name); } } @@ -540,7 +613,7 @@ get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, Mono static void set_message_on_exception (MonoException *exception, MonoErrorInternal *error, MonoError *error_out) { - MonoString *msg = mono_string_new (mono_domain_get (), error->full_message); + MonoString *msg = string_new_cleanup (mono_domain_get (), error->full_message); if (msg) MONO_OBJECT_SETREF (exception, message, msg); else @@ -557,7 +630,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) MonoString *assembly_name = NULL, *type_name = NULL, *method_name = NULL, *field_name = NULL, *msg = NULL; MonoDomain *domain = mono_domain_get (); - mono_error_init (error_out); + error_init (error_out); switch (error->error_code) { case MONO_ERROR_NONE: @@ -569,7 +642,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) if (!mono_error_ok (error_out)) break; - method_name = mono_string_new (domain, error->member_name); + method_name = string_new_cleanup (domain, error->member_name); if (!method_name) { mono_error_set_out_of_memory (error_out, "Could not allocate method name"); break; @@ -589,7 +662,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) if (!mono_error_ok (error_out)) break; - field_name = mono_string_new (domain, error->member_name); + field_name = string_new_cleanup (domain, error->member_name); if (!field_name) { mono_error_set_out_of_memory (error_out, "Could not allocate field name"); break; @@ -610,15 +683,17 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) break; if (error->assembly_name) { - assembly_name = mono_string_new (domain, error->assembly_name); + assembly_name = string_new_cleanup (domain, error->assembly_name); if (!assembly_name) { mono_error_set_out_of_memory (error_out, "Could not allocate assembly name"); break; } + } else { + assembly_name = mono_string_empty (domain); } exception = mono_exception_from_name_two_strings_checked (mono_get_corlib (), "System", "TypeLoadException", type_name, assembly_name, error_out); - if (exception) + 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); @@ -628,14 +703,14 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) case MONO_ERROR_FILE_NOT_FOUND: case MONO_ERROR_BAD_IMAGE: if (error->assembly_name) { - msg = mono_string_new (domain, error->full_message); + msg = string_new_cleanup (domain, error->full_message); if (!msg) { mono_error_set_out_of_memory (error_out, "Could not allocate message"); break; } if (error->assembly_name) { - assembly_name = mono_string_new (domain, error->assembly_name); + assembly_name = string_new_cleanup (domain, error->assembly_name); if (!assembly_name) { mono_error_set_out_of_memory (error_out, "Could not allocate assembly name"); break; @@ -730,6 +805,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; @@ -750,5 +828,95 @@ void mono_error_move (MonoError *dest, MonoError *src) { memcpy (dest, src, sizeof (MonoErrorInternal)); - mono_error_init (src); + error_init (src); +} + +/** + * mono_error_box: + * \param ierror The input error that will be boxed. + * \param image The mempool of this image will hold the boxed error. + * Creates a new boxed error in the given mempool from \c MonoError. + * It does not alter \p ierror, so you still have to clean it up with + * \c mono_error_cleanup or \c 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: + * \param oerror The error that will be set to the contents of the box. + * \param 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 \c mono_error_set_from_boxed as needed. The + * \p oerror should've been previously initialized with \c 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 ; }