2010-06-21 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / utils / mono-error.c
blobed080b959ca411c9fc64c94f1e6fc3b1c3d6198f
1 /*
2 * mono-error.c: Error handling code
4 * Authors:
5 * Rodrigo Kumpera (rkumpera@novell.com)
6 * Copyright 2009 Novell, Inc (http://www.novell.com)
7 */
8 #include <glib.h>
10 #include "mono-error.h"
11 #include "mono-error-internals.h"
13 #include <mono/metadata/exception.h>
14 #include <mono/metadata/object-internals.h>
15 #include <mono/metadata/debug-helpers.h>
17 #define mono_internal_error_get_message(E) ((E)->full_message ? (E)->full_message : (E)->message)
19 #define set_error_message() do { \
20 va_list args; \
21 va_start (args, msg_format); \
22 if (g_vsnprintf (error->message, sizeof (error->message), msg_format, args) >= sizeof (error->message)) {\
23 va_end (args); \
24 va_start (args, msg_format); \
25 if (!(error->full_message = g_strdup_vprintf (msg_format, args))) \
26 error->flags |= MONO_ERROR_INCOMPLETE; \
27 } \
28 va_end (args); \
29 } while (0)
31 static void
32 mono_error_prepare (MonoErrorInternal *error)
34 if (error->error_code != MONO_ERROR_NONE)
35 return;
37 error->type_name = error->assembly_name = error->member_name = error->full_message = error->exception_name_space = error->exception_name = NULL;
38 error->klass = NULL;
39 error->message [0] = 0;
42 void
43 mono_error_init_flags (MonoError *oerror, unsigned short flags)
45 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
46 g_assert (sizeof (MonoError) == sizeof (MonoErrorInternal));
48 error->error_code = MONO_ERROR_NONE;
49 error->flags = flags;
52 void
53 mono_error_init (MonoError *error)
55 mono_error_init_flags (error, 0);
58 void
59 mono_error_cleanup (MonoError *oerror)
61 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
62 if (error->error_code == MONO_ERROR_NONE)
63 return;
65 g_free ((char*)error->full_message);
66 if (!(error->flags & MONO_ERROR_FREE_STRINGS)) //no memory was allocated
67 return;
69 g_free ((char*)error->type_name);
70 g_free ((char*)error->assembly_name);
71 g_free ((char*)error->member_name);
72 g_free ((char*)error->exception_name_space);
73 g_free ((char*)error->exception_name);
76 gboolean
77 mono_error_ok (MonoError *error)
79 return error->error_code == MONO_ERROR_NONE;
82 unsigned short
83 mono_error_get_error_code (MonoError *error)
85 return error->error_code;
88 /*Return a pointer to the internal error message, might be NULL.
89 Caller should not release it.*/
90 const char*
91 mono_error_get_message (MonoError *oerror)
93 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
94 if (error->error_code == MONO_ERROR_NONE)
95 return NULL;
96 return mono_internal_error_get_message (error);
100 * Inform that this error has heap allocated strings.
101 * The strings will be duplicated if @dup_strings is TRUE
102 * otherwise they will just be free'd in mono_error_cleanup.
104 void
105 mono_error_dup_strings (MonoError *oerror, gboolean dup_strings)
107 #define DUP_STR(field) do { if (error->field) {\
108 if (!(error->field = g_strdup (error->field))) \
109 error->flags |= MONO_ERROR_INCOMPLETE; \
110 }} while (0);
112 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
113 error->flags |= MONO_ERROR_FREE_STRINGS;
115 if (dup_strings) {
116 DUP_STR (type_name);
117 DUP_STR (assembly_name);
118 DUP_STR (member_name);
119 DUP_STR (exception_name_space);
120 DUP_STR (exception_name);
122 #undef DUP_STR
125 void
126 mono_error_set_error (MonoError *oerror, int error_code, const char *msg_format, ...)
128 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
129 mono_error_prepare (error);
131 error->error_code = error_code;
132 set_error_message ();
135 static void
136 mono_error_set_assembly_name (MonoError *oerror, const char *assembly_name)
138 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
139 g_assert (error->error_code != MONO_ERROR_NONE);
141 error->assembly_name = assembly_name;
144 static void
145 mono_error_set_member_name (MonoError *oerror, const char *member_name)
147 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
149 error->member_name = member_name;
152 static void
153 mono_error_set_type_name (MonoError *oerror, const char *type_name)
155 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
157 error->type_name = type_name;
160 static void
161 mono_error_set_class (MonoError *oerror, MonoClass *klass)
163 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
165 error->klass = klass;
168 static void
169 mono_error_set_corlib_exception (MonoError *oerror, const char *name_space, const char *name)
171 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
173 error->exception_name_space = name_space;
174 error->exception_name = name;
178 void
179 mono_error_set_assembly_load (MonoError *oerror, const char *assembly_name, const char *msg_format, ...)
181 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
182 mono_error_prepare (error);
184 error->error_code = MONO_ERROR_FILE_NOT_FOUND;
185 mono_error_set_assembly_name (oerror, assembly_name);
187 set_error_message ();
190 void
191 mono_error_set_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, ...)
193 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
194 mono_error_prepare (error);
196 error->error_code = MONO_ERROR_TYPE_LOAD;
197 mono_error_set_class (oerror, klass);
198 set_error_message ();
201 void
202 mono_error_set_type_load_name (MonoError *oerror, const char *type_name, const char *assembly_name, const char *msg_format, ...)
204 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
205 mono_error_prepare (error);
207 error->error_code = MONO_ERROR_TYPE_LOAD;
208 mono_error_set_type_name (oerror, type_name);
209 mono_error_set_assembly_name (oerror, assembly_name);
210 set_error_message ();
213 void
214 mono_error_set_method_load (MonoError *oerror, MonoClass *klass, const char *method_name, const char *msg_format, ...)
216 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
217 mono_error_prepare (error);
219 error->error_code = MONO_ERROR_MISSING_METHOD;
220 mono_error_set_class (oerror, klass);
221 mono_error_set_member_name (oerror, method_name);
222 set_error_message ();
225 void
226 mono_error_set_field_load (MonoError *oerror, MonoClass *klass, const char *field_name, const char *msg_format, ...)
228 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
229 mono_error_prepare (error);
231 error->error_code = MONO_ERROR_MISSING_FIELD;
232 mono_error_set_class (oerror, klass);
233 mono_error_set_member_name (oerror, field_name);
234 set_error_message ();
237 void
238 mono_error_set_bad_image_name (MonoError *oerror, const char *assembly_name, const char *msg_format, ...)
240 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
241 mono_error_prepare (error);
243 error->error_code = MONO_ERROR_BAD_IMAGE;
244 mono_error_set_assembly_name (oerror, assembly_name);
245 set_error_message ();
248 void
249 mono_error_set_bad_image (MonoError *oerror, MonoImage *image, const char *msg_format, ...)
251 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
252 mono_error_prepare (error);
254 error->error_code = MONO_ERROR_BAD_IMAGE;
255 error->assembly_name = image ? mono_image_get_name (image) : "<no_image>";
256 set_error_message ();
259 void
260 mono_error_set_generic_error (MonoError *oerror, const char * name_space, const char *name, const char *msg_format, ...)
262 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
263 mono_error_prepare (error);
265 error->error_code = MONO_ERROR_GENERIC;
266 mono_error_set_corlib_exception (oerror, name_space, name);
267 set_error_message ();
270 void
271 mono_error_set_out_of_memory (MonoError *oerror, const char *msg_format, ...)
273 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
274 va_list args;
275 mono_error_prepare (error);
277 error->error_code = MONO_ERROR_OUT_OF_MEMORY;
278 va_start (args, msg_format);
279 g_vsnprintf (error->message, sizeof (error->message), msg_format, args);
280 va_end (args);
283 void
284 mono_error_set_argument (MonoError *oerror, const char *argument, const char *msg_format, ...)
286 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
287 mono_error_prepare (error);
289 error->error_code = MONO_ERROR_ARGUMENT;
290 error->type_name = argument; /*use the first available string slot*/
292 set_error_message ();
295 void
296 mono_error_set_not_verifiable (MonoError *oerror, MonoMethod *method, const char *msg_format, ...)
298 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
299 mono_error_prepare (error);
301 error->error_code = MONO_ERROR_NOT_VERIFIABLE;
302 mono_error_set_class (oerror, method->klass);
303 if (method)
304 mono_error_set_member_name (oerror, mono_method_full_name (method, 1));
306 set_error_message ();
310 static MonoString*
311 get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, MonoError *error_out)
313 MonoString* res = NULL;
315 if (error->type_name) {
316 res = mono_string_new (domain, error->type_name);
318 } else if (error->klass) {
319 char *name = mono_type_full_name (&error->klass->byval_arg);
320 if (name) {
321 res = mono_string_new (domain, name);
322 g_free (name);
325 if (!res)
326 mono_error_set_out_of_memory (error_out, "Could not allocate type name");
327 return res;
330 static void
331 set_message_on_exception (MonoException *exception, MonoErrorInternal *error, MonoError *error_out)
333 MonoString *msg = mono_string_new (mono_domain_get (), mono_internal_error_get_message (error));
334 if (msg)
335 MONO_OBJECT_SETREF (exception, message, msg);
336 else
337 mono_error_set_out_of_memory (error_out, "Could not allocate exception object");
340 /*Can fail with out-of-memory*/
341 MonoException*
342 mono_error_prepare_exception (MonoError *oerror, MonoError *error_out)
344 MonoErrorInternal *error = (MonoErrorInternal*)oerror;
346 MonoException* exception = NULL;
347 MonoString *assembly_name = NULL, *type_name = NULL, *method_name = NULL, *field_name = NULL, *msg = NULL;
348 MonoDomain *domain = mono_domain_get ();
350 mono_error_init (error_out);
352 switch (error->error_code) {
353 case MONO_ERROR_NONE:
354 return NULL;
356 case MONO_ERROR_MISSING_METHOD:
357 if ((error->type_name || error->klass) && error->member_name) {
358 type_name = get_type_name_as_mono_string (error, domain, error_out);
359 if (!mono_error_ok (error_out))
360 break;
362 method_name = mono_string_new (domain, error->member_name);
363 if (!method_name) {
364 mono_error_set_out_of_memory (error_out, "Could not allocate method name");
365 break;
368 exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "MissingMethodException", type_name, method_name);
369 if (exception)
370 set_message_on_exception (exception, error, error_out);
371 } else {
372 exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", mono_internal_error_get_message (error));
374 break;
376 case MONO_ERROR_MISSING_FIELD:
377 if ((error->type_name || error->klass) && error->member_name) {
378 type_name = get_type_name_as_mono_string (error, domain, error_out);
379 if (!mono_error_ok (error_out))
380 break;
382 field_name = mono_string_new (domain, error->member_name);
383 if (!field_name) {
384 mono_error_set_out_of_memory (error_out, "Could not allocate field name");
385 break;
388 exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "MissingFieldException", type_name, field_name);
389 if (exception)
390 set_message_on_exception (exception, error, error_out);
391 } else {
392 exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", mono_internal_error_get_message (error));
394 break;
396 case MONO_ERROR_TYPE_LOAD:
397 if (error->type_name || error->assembly_name) {
398 type_name = get_type_name_as_mono_string (error, domain, error_out);
399 if (!mono_error_ok (error_out))
400 break;
402 if (error->assembly_name) {
403 assembly_name = mono_string_new (domain, error->assembly_name);
404 if (!assembly_name) {
405 mono_error_set_out_of_memory (error_out, "Could not allocate assembly name");
406 break;
410 exception = mono_exception_from_name_two_strings (mono_get_corlib (), "System", "TypeLoadException", type_name, assembly_name);
411 if (exception)
412 set_message_on_exception (exception, error, error_out);
413 } else {
414 exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", mono_internal_error_get_message (error));
416 break;
418 case MONO_ERROR_FILE_NOT_FOUND:
419 case MONO_ERROR_BAD_IMAGE:
420 if (error->assembly_name) {
421 msg = mono_string_new (domain, mono_internal_error_get_message (error));
422 if (!msg) {
423 mono_error_set_out_of_memory (error_out, "Could not allocate message");
424 break;
427 if (error->assembly_name) {
428 assembly_name = mono_string_new (domain, error->assembly_name);
429 if (!assembly_name) {
430 mono_error_set_out_of_memory (error_out, "Could not allocate assembly name");
431 break;
435 if (error->error_code == MONO_ERROR_FILE_NOT_FOUND)
436 exception = mono_exception_from_name_two_strings (mono_get_corlib (), "System.IO", "FileNotFoundException", msg, assembly_name);
437 else
438 exception = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "BadImageFormatException", msg, assembly_name);
439 } else {
440 if (error->error_code == MONO_ERROR_FILE_NOT_FOUND)
441 exception = mono_exception_from_name_msg (mono_get_corlib (), "System.IO", "FileNotFoundException", mono_internal_error_get_message (error));
442 else
443 exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "BadImageFormatException", mono_internal_error_get_message (error));
445 break;
447 case MONO_ERROR_OUT_OF_MEMORY:
448 exception = mono_get_exception_out_of_memory ();
449 break;
451 case MONO_ERROR_ARGUMENT:
452 exception = mono_get_exception_argument (error->type_name, mono_internal_error_get_message (error));
453 break;
455 case MONO_ERROR_NOT_VERIFIABLE: {
456 char *type_name = NULL, *message;
457 if (error->klass) {
458 type_name = mono_type_get_full_name (error->klass);
459 if (!type_name) {
460 mono_error_set_out_of_memory (error_out, "Could not allocate message");
461 break;
464 message = g_strdup_printf ("Error in %s:%s %s", type_name, error->member_name, mono_internal_error_get_message (error));
465 if (!message) {
466 g_free (type_name);
467 mono_error_set_out_of_memory (error_out, "Could not allocate message");
468 break;
470 exception = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", message);
471 g_free (message);
472 g_free (type_name);
473 break;
475 case MONO_ERROR_GENERIC:
476 if (!error->exception_name_space || !error->exception_name)
477 mono_error_set_generic_error (error_out, "System", "ExecutionEngineException", "MonoError with generic error but no exception name was supplied");
478 else
479 exception = mono_exception_from_name_msg (mono_defaults.corlib, error->exception_name_space, error->exception_name, mono_internal_error_get_message (error));
480 break;
482 default:
483 mono_error_set_generic_error (error_out, "System", "ExecutionEngineException", "Invalid error-code %d", error->error_code);
486 if (!mono_error_ok (error_out))
487 return NULL;
488 if (!exception)
489 mono_error_set_out_of_memory (error_out, "Could not allocate exception object");
490 return exception;
494 Raises the exception of @error.
495 Does nothing if @error has a success error code.
496 Aborts in case of a double fault. This happens when it can't recover from an error caused by trying
497 to construct the first exception object.
498 The error object @error is cleaned up.
500 void
501 mono_error_raise_exception (MonoError *target_error)
503 MonoError error;
504 MonoException *ex;
506 if (mono_error_ok (target_error))
507 return;
509 ex = mono_error_prepare_exception (target_error, &error);
510 if (!mono_error_ok (&error)) {
511 MonoError second_chance;
512 /*Try to produce the exception for the second error. FIXME maybe we should log about the original one*/
513 ex = mono_error_prepare_exception (&error, &second_chance);
515 g_assert (mono_error_ok (&second_chance)); /*We can't reasonable handle double faults, maybe later.*/
516 mono_error_cleanup (&error);
518 mono_error_cleanup (target_error);
520 mono_raise_exception (ex);