PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/mono/utils/mono-error.c

http://github.com/mono/mono
C | 910 lines | 670 code | 141 blank | 99 comment | 78 complexity | 4a089a937aefe7cd646481b64ab37e5f MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  1. /**
  2. * \file
  3. * Error handling code
  4. *
  5. * Authors:
  6. * Rodrigo Kumpera (rkumpera@novell.com)
  7. * Copyright 2009 Novell, Inc (http://www.novell.com)
  8. * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  9. */
  10. #include <glib.h>
  11. #include <config.h>
  12. #include "mono-error.h"
  13. #include "mono-error-internals.h"
  14. #include <mono/metadata/exception.h>
  15. #include <mono/metadata/exception-internals.h>
  16. #include <mono/metadata/debug-helpers.h>
  17. #include <mono/metadata/object-internals.h>
  18. #define set_error_messagev() do { \
  19. if (msg_format && !(error->full_message = g_strdup_vprintf (msg_format, args))) \
  20. error->flags |= MONO_ERROR_INCOMPLETE; \
  21. } while (0)
  22. #define set_error_message() do { \
  23. va_list args; \
  24. va_start (args, msg_format); \
  25. set_error_messagev(); \
  26. va_end (args); \
  27. } while (0)
  28. static void
  29. mono_error_set_generic_errorv (MonoError *oerror, const char *name_space, const char *name, const char *msg_format, va_list args);
  30. static gboolean
  31. is_managed_error_code (guint16 error_code)
  32. {
  33. return error_code == MONO_ERROR_EXCEPTION_INSTANCE;
  34. }
  35. static gboolean
  36. is_managed_exception (MonoErrorInternal *error)
  37. {
  38. return is_managed_error_code (error->error_code);
  39. }
  40. static gboolean
  41. is_boxed_error_flags (guint16 error_flags)
  42. {
  43. return (error_flags & MONO_ERROR_MEMPOOL_BOXED) != 0;
  44. }
  45. static gboolean
  46. is_boxed (MonoErrorInternal *error)
  47. {
  48. return is_boxed_error_flags (error->flags);
  49. }
  50. static void
  51. mono_error_free_string (const char **error_string)
  52. {
  53. g_free ((char*)*error_string);
  54. *error_string = NULL;
  55. }
  56. static void
  57. mono_error_init_deferred (MonoErrorInternal *error)
  58. // mono_error_init and mono_error_init_flags are optimized and only initialize a minimum.
  59. // Initialize the rest, prior to originating an error.
  60. {
  61. memset (&error->type_name, 0, sizeof (*error) - offsetof (MonoErrorInternal, type_name));
  62. }
  63. static void
  64. mono_error_prepare (MonoErrorInternal *error)
  65. {
  66. /* mono_error_set_* after a mono_error_cleanup without an intervening init */
  67. g_assert (error->error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL);
  68. if (error->error_code != MONO_ERROR_NONE)
  69. return;
  70. mono_error_init_deferred (error);
  71. }
  72. static MonoClass*
  73. get_class (MonoErrorInternal *error)
  74. {
  75. MonoClass *klass = NULL;
  76. if (is_managed_exception (error))
  77. klass = mono_object_class (mono_gchandle_get_target_internal (error->exn.instance_handle));
  78. else
  79. klass = error->exn.klass;
  80. return klass;
  81. }
  82. static const char*
  83. get_type_name (MonoErrorInternal *error)
  84. {
  85. if (error->type_name)
  86. return error->type_name;
  87. MonoClass *klass = get_class (error);
  88. if (klass)
  89. return m_class_get_name (klass);
  90. return "<unknown type>";
  91. }
  92. static const char*
  93. get_assembly_name (MonoErrorInternal *error)
  94. {
  95. if (error->assembly_name)
  96. return error->assembly_name;
  97. MonoClass *klass = get_class (error);
  98. if (klass && m_class_get_image (klass))
  99. return m_class_get_image (klass)->name;
  100. return "<unknown assembly>";
  101. }
  102. void
  103. mono_error_init_flags (MonoError *oerror, guint16 flags)
  104. {
  105. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  106. g_static_assert (sizeof (MonoErrorExternal) >= sizeof (MonoErrorInternal));
  107. error->error_code = MONO_ERROR_NONE;
  108. error->flags = flags;
  109. }
  110. /**
  111. * mono_error_init:
  112. * \param error Pointer to \c MonoError struct to initialize
  113. * Any function which takes a \c MonoError for purposes of reporting an error
  114. * is required to call either this or \c mono_error_init_flags on entry.
  115. */
  116. void
  117. mono_error_init (MonoError *error)
  118. {
  119. mono_error_init_flags (error, 0);
  120. }
  121. void
  122. mono_error_cleanup (MonoError *oerror)
  123. {
  124. // This function is called a lot so it is optimized.
  125. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  126. #if G_BYTE_ORDER == G_LITTLE_ENDIAN
  127. const guint32 init = oerror->init;
  128. const guint16 error_code = (guint16)(init & 0xFFFF);
  129. const guint16 error_flags = (guint16)(init >> 16);
  130. #else
  131. const guint16 error_code = error->error_code;
  132. const guint16 error_flags = error->flags;
  133. #endif
  134. /* Two cleanups in a row without an intervening init. */
  135. g_assert (error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL);
  136. /* Mempool stored error shouldn't be cleaned up */
  137. g_assert (!is_boxed_error_flags (error_flags));
  138. /* Mark it as cleaned up. */
  139. #if G_BYTE_ORDER == G_LITTLE_ENDIAN
  140. oerror->init = MONO_ERROR_CLEANUP_CALLED_SENTINEL;
  141. #else
  142. error->error_code = MONO_ERROR_CLEANUP_CALLED_SENTINEL;
  143. error->flags = 0;
  144. #endif
  145. if (error_code == MONO_ERROR_NONE)
  146. return;
  147. if (is_managed_error_code (error_code))
  148. mono_gchandle_free_internal (error->exn.instance_handle);
  149. mono_error_free_string (&error->full_message);
  150. mono_error_free_string (&error->full_message_with_fields);
  151. if (!(error_flags & MONO_ERROR_FREE_STRINGS)) //no memory was allocated
  152. return;
  153. mono_error_free_string (&error->type_name);
  154. mono_error_free_string (&error->assembly_name);
  155. mono_error_free_string (&error->member_name);
  156. mono_error_free_string (&error->exception_name_space);
  157. mono_error_free_string (&error->exception_name);
  158. mono_error_free_string (&error->first_argument);
  159. error->exn.klass = NULL;
  160. }
  161. gboolean
  162. mono_error_ok (MonoError *error)
  163. {
  164. return is_ok (error);
  165. }
  166. guint16
  167. mono_error_get_error_code (MonoError *error)
  168. {
  169. return error->error_code;
  170. }
  171. const char*
  172. mono_error_get_exception_name (MonoError *oerror)
  173. {
  174. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  175. if (error->error_code == MONO_ERROR_NONE)
  176. return NULL;
  177. return error->exception_name;
  178. }
  179. /*Return a pointer to the internal error message, might be NULL.
  180. Caller should not release it.*/
  181. const char*
  182. mono_error_get_message (MonoError *oerror)
  183. {
  184. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  185. const guint16 error_code = error->error_code;
  186. if (error_code == MONO_ERROR_NONE)
  187. return NULL;
  188. g_assert (error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL);
  189. //Those are the simplified errors
  190. switch (error_code) {
  191. case MONO_ERROR_MISSING_METHOD:
  192. case MONO_ERROR_BAD_IMAGE:
  193. case MONO_ERROR_FILE_NOT_FOUND:
  194. case MONO_ERROR_MISSING_FIELD:
  195. return error->full_message;
  196. }
  197. if (error->full_message_with_fields)
  198. return error->full_message_with_fields;
  199. error->full_message_with_fields = g_strdup_printf ("%s assembly:%s type:%s member:%s",
  200. error->full_message,
  201. get_assembly_name (error),
  202. get_type_name (error),
  203. error->member_name);
  204. return error->full_message_with_fields ? error->full_message_with_fields : error->full_message;
  205. }
  206. /*
  207. * Inform that this error has heap allocated strings.
  208. * The strings will be duplicated if @dup_strings is TRUE
  209. * otherwise they will just be free'd in mono_error_cleanup.
  210. */
  211. void
  212. mono_error_dup_strings (MonoError *oerror, gboolean dup_strings)
  213. {
  214. #define DUP_STR(field) do { if (error->field) {\
  215. if (!(error->field = g_strdup (error->field))) \
  216. error->flags |= MONO_ERROR_INCOMPLETE; \
  217. }} while (0);
  218. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  219. error->flags |= MONO_ERROR_FREE_STRINGS;
  220. if (dup_strings) {
  221. DUP_STR (type_name);
  222. DUP_STR (assembly_name);
  223. DUP_STR (member_name);
  224. DUP_STR (exception_name_space);
  225. DUP_STR (exception_name);
  226. DUP_STR (first_argument);
  227. }
  228. #undef DUP_STR
  229. }
  230. void
  231. mono_error_set_error (MonoError *oerror, int error_code, const char *msg_format, ...)
  232. {
  233. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  234. mono_error_prepare (error);
  235. error->error_code = error_code;
  236. set_error_message ();
  237. }
  238. static void
  239. mono_error_set_assembly_name (MonoError *oerror, const char *assembly_name)
  240. {
  241. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  242. g_assert (error->error_code != MONO_ERROR_NONE);
  243. error->assembly_name = assembly_name;
  244. }
  245. static void
  246. mono_error_set_member_name (MonoError *oerror, const char *member_name)
  247. {
  248. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  249. error->member_name = member_name;
  250. }
  251. static void
  252. mono_error_set_type_name (MonoError *oerror, const char *type_name)
  253. {
  254. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  255. error->type_name = type_name;
  256. }
  257. static void
  258. mono_error_set_class (MonoError *oerror, MonoClass *klass)
  259. {
  260. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  261. if (is_managed_exception (error))
  262. return;
  263. error->exn.klass = klass;
  264. }
  265. static void
  266. mono_error_set_corlib_exception (MonoError *oerror, const char *name_space, const char *name)
  267. {
  268. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  269. error->exception_name_space = name_space;
  270. error->exception_name = name;
  271. }
  272. void
  273. mono_error_set_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, ...)
  274. {
  275. va_list args;
  276. va_start (args, msg_format);
  277. mono_error_vset_type_load_class (oerror, klass, msg_format, args);
  278. va_end (args);
  279. }
  280. void
  281. mono_error_vset_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, va_list args)
  282. {
  283. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  284. mono_error_prepare (error);
  285. error->error_code = MONO_ERROR_TYPE_LOAD;
  286. mono_error_set_class (oerror, klass);
  287. set_error_messagev ();
  288. }
  289. /*
  290. * Different than other functions, this one here assumes that type_name and assembly_name to have been allocated just for us.
  291. * Which means mono_error_cleanup will free them.
  292. */
  293. void
  294. mono_error_set_type_load_name (MonoError *oerror, const char *type_name, const char *assembly_name, const char *msg_format, ...)
  295. {
  296. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  297. mono_error_prepare (error);
  298. error->error_code = MONO_ERROR_TYPE_LOAD;
  299. mono_error_set_type_name (oerror, type_name);
  300. mono_error_set_assembly_name (oerror, assembly_name);
  301. mono_error_dup_strings (oerror, FALSE);
  302. set_error_message ();
  303. }
  304. /*
  305. * Sets @error to be of type @error_code with message @message
  306. * XXX only works for MONO_ERROR_MISSING_METHOD, MONO_ERROR_BAD_IMAGE, MONO_ERROR_FILE_NOT_FOUND and MONO_ERROR_MISSING_FIELD for now
  307. */
  308. void
  309. mono_error_set_specific (MonoError *oerror, int error_code, const char *message)
  310. {
  311. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  312. mono_error_prepare (error);
  313. error->error_code = error_code;
  314. error->full_message = message;
  315. error->flags |= MONO_ERROR_FREE_STRINGS;
  316. }
  317. void
  318. mono_error_set_generic_errorv (MonoError *oerror, const char *name_space, const char *name, const char *msg_format, va_list args)
  319. {
  320. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  321. mono_error_prepare (error);
  322. error->error_code = MONO_ERROR_GENERIC;
  323. mono_error_set_corlib_exception (oerror, name_space, name);
  324. set_error_messagev ();
  325. }
  326. void
  327. mono_error_set_generic_error (MonoError *oerror, const char * name_space, const char *name, const char *msg_format, ...)
  328. {
  329. va_list args;
  330. va_start (args, msg_format);
  331. mono_error_set_generic_errorv (oerror, name_space, name, msg_format, args);
  332. va_end (args);
  333. }
  334. /**
  335. * mono_error_set_not_implemented:
  336. *
  337. * System.NotImplementedException
  338. */
  339. void
  340. mono_error_set_not_implemented (MonoError *oerror, const char *msg_format, ...)
  341. {
  342. va_list args;
  343. va_start (args, msg_format);
  344. mono_error_set_generic_errorv (oerror, "System", "NotImplementedException", msg_format, args);
  345. va_end (args);
  346. }
  347. /**
  348. * mono_error_set_execution_engine:
  349. *
  350. * System.ExecutionEngineException
  351. */
  352. void
  353. mono_error_set_execution_engine (MonoError *oerror, const char *msg_format, ...)
  354. {
  355. va_list args;
  356. va_start (args, msg_format);
  357. mono_error_set_generic_errorv (oerror, "System", "ExecutionEngineException", msg_format, args);
  358. va_end (args);
  359. }
  360. /**
  361. * mono_error_set_not_supported:
  362. *
  363. * System.NotSupportedException
  364. */
  365. void
  366. mono_error_set_not_supported (MonoError *oerror, const char *msg_format, ...)
  367. {
  368. va_list args;
  369. va_start (args, msg_format);
  370. mono_error_set_generic_errorv (oerror, "System", "NotSupportedException", msg_format, args);
  371. va_end (args);
  372. }
  373. /**
  374. * mono_error_set_ambiguous_implementation:
  375. *
  376. * System.Runtime.AmbiguousImplementationException
  377. */
  378. void
  379. mono_error_set_ambiguous_implementation (MonoError *oerror, const char *msg_format, ...)
  380. {
  381. va_list args;
  382. va_start (args, msg_format);
  383. mono_error_set_generic_errorv (oerror, "System.Runtime", "AmbiguousImplementationException", msg_format, args);
  384. va_end (args);
  385. }
  386. /**
  387. * mono_error_set_invalid_operation:
  388. *
  389. * System.InvalidOperationException
  390. */
  391. void
  392. mono_error_set_invalid_operation (MonoError *oerror, const char *msg_format, ...)
  393. {
  394. va_list args;
  395. va_start (args, msg_format);
  396. mono_error_set_generic_errorv (oerror, "System", "InvalidOperationException", msg_format, args);
  397. va_end (args);
  398. }
  399. void
  400. mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...)
  401. {
  402. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  403. mono_error_prepare (error);
  404. error->error_code = MONO_ERROR_INVALID_PROGRAM;
  405. set_error_message ();
  406. }
  407. void
  408. mono_error_set_member_access (MonoError *oerror, const char *msg_format, ...)
  409. {
  410. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  411. mono_error_prepare (error);
  412. error->error_code = MONO_ERROR_MEMBER_ACCESS;
  413. set_error_message ();
  414. }
  415. /**
  416. * mono_error_set_invalid_cast:
  417. *
  418. * System.InvalidCastException
  419. */
  420. void
  421. mono_error_set_invalid_cast (MonoError *oerror)
  422. {
  423. mono_error_set_generic_error (oerror, "System", "InvalidCastException", "");
  424. }
  425. void
  426. mono_error_set_exception_instance (MonoError *oerror, MonoException *exc)
  427. {
  428. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  429. mono_error_prepare (error);
  430. error->error_code = MONO_ERROR_EXCEPTION_INSTANCE;
  431. error->exn.instance_handle = mono_gchandle_new_internal (exc ? &exc->object : NULL, FALSE);
  432. }
  433. void
  434. mono_error_set_exception_handle (MonoError *oerror, MonoExceptionHandle exc)
  435. {
  436. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  437. mono_error_prepare (error);
  438. error->error_code = MONO_ERROR_EXCEPTION_INSTANCE;
  439. error->exn.instance_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST(MonoObject, exc), FALSE);
  440. }
  441. void
  442. mono_error_set_out_of_memory (MonoError *oerror, const char *msg_format, ...)
  443. {
  444. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  445. mono_error_prepare (error);
  446. error->error_code = MONO_ERROR_OUT_OF_MEMORY;
  447. set_error_message ();
  448. }
  449. void
  450. mono_error_set_argument_format (MonoError *oerror, const char *argument, const char *msg_format, ...)
  451. {
  452. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  453. mono_error_prepare (error);
  454. error->error_code = MONO_ERROR_ARGUMENT;
  455. error->first_argument = argument;
  456. set_error_message ();
  457. }
  458. void
  459. mono_error_set_argument (MonoError *oerror, const char *argument, const char *msg)
  460. {
  461. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  462. mono_error_prepare (error);
  463. error->error_code = MONO_ERROR_ARGUMENT;
  464. error->first_argument = argument;
  465. if (msg && msg [0] && !(error->full_message = g_strdup (msg)))
  466. error->flags |= MONO_ERROR_INCOMPLETE;
  467. }
  468. void
  469. mono_error_set_argument_null (MonoError *oerror, const char *argument, const char *msg_format, ...)
  470. {
  471. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  472. mono_error_prepare (error);
  473. error->error_code = MONO_ERROR_ARGUMENT_NULL;
  474. error->first_argument = argument;
  475. set_error_message ();
  476. }
  477. void
  478. mono_error_set_not_verifiable (MonoError *oerror, MonoMethod *method, const char *msg_format, ...)
  479. {
  480. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  481. mono_error_prepare (error);
  482. error->error_code = MONO_ERROR_NOT_VERIFIABLE;
  483. if (method) {
  484. mono_error_set_class (oerror, method->klass);
  485. mono_error_set_member_name (oerror, mono_method_full_name (method, 1));
  486. }
  487. set_error_message ();
  488. }
  489. /* Used by mono_error_prepare_exception - it sets its own error on mono_string_new_checked failure. */
  490. static MonoStringHandle
  491. string_new_cleanup (MonoDomain *domain, const char *text)
  492. {
  493. ERROR_DECL (ignored_err);
  494. MonoStringHandle result = mono_string_new_handle (domain, text, ignored_err);
  495. mono_error_cleanup (ignored_err);
  496. return result;
  497. }
  498. static MonoStringHandle
  499. get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, MonoError *error_out)
  500. {
  501. HANDLE_FUNCTION_ENTER ();
  502. MonoStringHandle res = NULL_HANDLE_STRING;
  503. if (error->type_name) {
  504. res = string_new_cleanup (domain, error->type_name);
  505. } else {
  506. MonoClass *klass = get_class (error);
  507. if (klass) {
  508. char *name = mono_type_full_name (m_class_get_byval_arg (klass));
  509. if (name) {
  510. res = string_new_cleanup (domain, name);
  511. g_free (name);
  512. }
  513. }
  514. }
  515. if (MONO_HANDLE_IS_NULL (res))
  516. mono_error_set_out_of_memory (error_out, "Could not allocate type name");
  517. HANDLE_FUNCTION_RETURN_REF (MonoString, res);
  518. }
  519. #if 0
  520. static MonoExceptionHandle
  521. mono_error_prepare_exception_handle (MonoError *oerror, MonoError *error_out)
  522. // Can fail with out-of-memory
  523. {
  524. HANDLE_FUNCTION_ENTER ();
  525. MonoExceptionHandle ex = MONO_HANDLE_NEW (MonoException, mono_error_prepare_exception (oerror, error_out));
  526. HANDLE_FUNCTION_RETURN_REF (MonoException, ex);
  527. }
  528. #endif
  529. /*Can fail with out-of-memory*/
  530. MonoException*
  531. mono_error_prepare_exception (MonoError *oerror, MonoError *error_out)
  532. {
  533. HANDLE_FUNCTION_ENTER ();
  534. MonoErrorInternal *error = (MonoErrorInternal*)oerror;
  535. MonoExceptionHandle exception = MONO_HANDLE_CAST (MonoException, mono_new_null ());
  536. MonoDomain *domain = mono_domain_get ();
  537. char *type_name = NULL;
  538. char *message = NULL;
  539. error_init (error_out);
  540. const guint16 error_code = error->error_code;
  541. g_assert (error_code != MONO_ERROR_CLEANUP_CALLED_SENTINEL);
  542. switch (error_code) {
  543. case MONO_ERROR_NONE:
  544. goto exit;
  545. case MONO_ERROR_MISSING_METHOD:
  546. exception = mono_corlib_exception_new_with_args ("System", "MissingMethodException", error->full_message, error->first_argument, error_out);
  547. break;
  548. case MONO_ERROR_BAD_IMAGE:
  549. exception = mono_corlib_exception_new_with_args ("System", "BadImageFormatException", error->full_message, error->first_argument, error_out);
  550. break;
  551. case MONO_ERROR_FILE_NOT_FOUND:
  552. exception = mono_corlib_exception_new_with_args ("System.IO", "FileNotFoundException", error->full_message, error->first_argument, error_out);
  553. break;
  554. case MONO_ERROR_MISSING_FIELD:
  555. exception = mono_corlib_exception_new_with_args ("System", "MissingFieldException", error->full_message, error->first_argument, error_out);
  556. break;
  557. case MONO_ERROR_MEMBER_ACCESS:
  558. exception = mono_exception_new_by_name_msg (mono_defaults.corlib, "System", "MemberAccessException", error->full_message, error_out);
  559. break;
  560. case MONO_ERROR_TYPE_LOAD: {
  561. MonoStringHandle assembly_name;
  562. MonoStringHandle type_name;
  563. if ((error->type_name && error->assembly_name) || error->exn.klass) {
  564. type_name = get_type_name_as_mono_string (error, domain, error_out);
  565. if (!is_ok (error_out))
  566. break;
  567. if (error->assembly_name) {
  568. assembly_name = string_new_cleanup (domain, error->assembly_name);
  569. if (MONO_HANDLE_IS_NULL (assembly_name)) {
  570. mono_error_set_out_of_memory (error_out, "Could not allocate assembly name");
  571. break;
  572. }
  573. } else {
  574. assembly_name = mono_string_empty_handle (domain);
  575. }
  576. exception = mono_exception_from_name_two_strings_checked (mono_get_corlib (), "System", "TypeLoadException", type_name, assembly_name, error_out);
  577. if (!MONO_HANDLE_IS_NULL (exception)) {
  578. const char *full_message = error->full_message;
  579. if (full_message && full_message [0]) {
  580. MonoStringHandle msg = string_new_cleanup (mono_domain_get (), full_message);
  581. if (!MONO_HANDLE_IS_NULL (msg))
  582. MONO_HANDLE_SET (exception, message, msg);
  583. else
  584. mono_error_set_out_of_memory (error_out, "Could not allocate exception object");
  585. }
  586. }
  587. } else {
  588. exception = mono_exception_new_by_name_msg (mono_defaults.corlib, "System", "TypeLoadException", error->full_message, error_out);
  589. }
  590. }
  591. break;
  592. case MONO_ERROR_OUT_OF_MEMORY:
  593. if (domain)
  594. exception = MONO_HANDLE_NEW (MonoException, domain->out_of_memory_ex);
  595. if (MONO_HANDLE_IS_NULL (exception))
  596. exception = mono_get_exception_out_of_memory_handle ();
  597. break;
  598. case MONO_ERROR_ARGUMENT:
  599. exception = mono_exception_new_argument (error->first_argument, error->full_message, error_out);
  600. break;
  601. case MONO_ERROR_ARGUMENT_NULL:
  602. exception = mono_exception_new_argument_null (error->first_argument, error_out);
  603. break;
  604. case MONO_ERROR_ARGUMENT_OUT_OF_RANGE:
  605. exception = mono_exception_new_argument_out_of_range(error->first_argument, error->full_message, error_out);
  606. break;
  607. case MONO_ERROR_NOT_VERIFIABLE:
  608. if (error->exn.klass) {
  609. type_name = mono_type_get_full_name (error->exn.klass);
  610. if (!type_name)
  611. goto out_of_memory;
  612. }
  613. message = g_strdup_printf ("Error in %s:%s %s", type_name, error->member_name, error->full_message);
  614. if (!message)
  615. goto out_of_memory;
  616. exception = mono_exception_new_by_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", message, error_out);
  617. break;
  618. case MONO_ERROR_GENERIC:
  619. if (!error->exception_name_space || !error->exception_name)
  620. mono_error_set_execution_engine (error_out, "MonoError with generic error but no exception name was supplied");
  621. else
  622. exception = mono_exception_new_by_name_msg (mono_defaults.corlib, error->exception_name_space, error->exception_name, error->full_message, error_out);
  623. break;
  624. case MONO_ERROR_EXCEPTION_INSTANCE:
  625. exception = MONO_HANDLE_CAST (MonoException, mono_gchandle_get_target_handle (error->exn.instance_handle));
  626. break;
  627. case MONO_ERROR_CLEANUP_CALLED_SENTINEL:
  628. mono_error_set_execution_engine (error_out, "MonoError reused after mono_error_cleanup");
  629. break;
  630. case MONO_ERROR_INVALID_PROGRAM:
  631. exception = mono_exception_new_by_name_msg (mono_defaults.corlib, "System", "InvalidProgramException",
  632. (error->flags & MONO_ERROR_INCOMPLETE) ? "" : error->full_message, error_out);
  633. break;
  634. default:
  635. mono_error_set_execution_engine (error_out, "Invalid error-code %d", error->error_code);
  636. }
  637. if (!is_ok (error_out))
  638. goto return_null;
  639. if (MONO_HANDLE_IS_NULL (exception))
  640. mono_error_set_out_of_memory (error_out, "Could not allocate exception object");
  641. goto exit;
  642. out_of_memory:
  643. mono_error_set_out_of_memory (error_out, "Could not allocate message");
  644. goto exit;
  645. return_null:
  646. exception = MONO_HANDLE_CAST (MonoException, mono_new_null ());
  647. exit:
  648. g_free (message);
  649. g_free (type_name);
  650. HANDLE_FUNCTION_RETURN_OBJ (exception);
  651. }
  652. /*
  653. Convert this MonoError to an exception if it's faulty or return NULL.
  654. The error object is cleant after.
  655. */
  656. MonoException*
  657. mono_error_convert_to_exception (MonoError *target_error)
  658. {
  659. ERROR_DECL (error);
  660. MonoException *ex;
  661. /* Mempool stored error shouldn't be cleaned up */
  662. g_assert (!is_boxed ((MonoErrorInternal*)target_error));
  663. if (is_ok (target_error))
  664. return NULL;
  665. ex = mono_error_prepare_exception (target_error, error);
  666. if (!is_ok (error)) {
  667. ERROR_DECL (second_chance);
  668. /*Try to produce the exception for the second error. FIXME maybe we should log about the original one*/
  669. ex = mono_error_prepare_exception (error, second_chance);
  670. // We cannot reasonably handle double faults, maybe later.
  671. g_assert (is_ok (second_chance));
  672. mono_error_cleanup (error);
  673. }
  674. mono_error_cleanup (target_error);
  675. return ex;
  676. }
  677. void
  678. mono_error_move (MonoError *dest, MonoError *src)
  679. {
  680. memcpy (dest, src, sizeof (MonoErrorInternal));
  681. error_init (src);
  682. }
  683. /**
  684. * mono_error_box:
  685. * \param ierror The input error that will be boxed.
  686. * \param image The mempool of this image will hold the boxed error.
  687. * Creates a new boxed error in the given mempool from \c MonoError.
  688. * It does not alter \p ierror, so you still have to clean it up with
  689. * \c mono_error_cleanup or \c mono_error_convert_to_exception or another such function.
  690. * \returns the boxed error, or NULL if the mempool could not allocate.
  691. */
  692. MonoErrorBoxed*
  693. mono_error_box (const MonoError *ierror, MonoImage *image)
  694. {
  695. MonoErrorInternal *from = (MonoErrorInternal*)ierror;
  696. /* Don't know how to box a gchandle */
  697. g_assert (!is_managed_exception (from));
  698. MonoErrorBoxed* box = (MonoErrorBoxed*)mono_image_alloc (image, sizeof (MonoErrorBoxed));
  699. box->image = image;
  700. mono_error_init_flags (&box->error, MONO_ERROR_MEMPOOL_BOXED);
  701. MonoErrorInternal *to = (MonoErrorInternal*)&box->error;
  702. #define DUP_STR(field) do { \
  703. if (from->field) { \
  704. if (!(to->field = mono_image_strdup (image, from->field))) \
  705. to->flags |= MONO_ERROR_INCOMPLETE; \
  706. } else { \
  707. to->field = NULL; \
  708. } \
  709. } while (0)
  710. to->error_code = from->error_code;
  711. DUP_STR (type_name);
  712. DUP_STR (assembly_name);
  713. DUP_STR (member_name);
  714. DUP_STR (exception_name_space);
  715. DUP_STR (exception_name);
  716. DUP_STR (full_message);
  717. DUP_STR (full_message_with_fields);
  718. DUP_STR (first_argument);
  719. to->exn.klass = from->exn.klass;
  720. #undef DUP_STR
  721. return box;
  722. }
  723. /**
  724. * mono_error_set_from_boxed:
  725. * \param oerror The error that will be set to the contents of the box.
  726. * \param box A mempool-allocated error.
  727. * Sets the error condition in the oerror from the contents of the
  728. * given boxed error. Does not alter the boxed error, so it can be
  729. * used in a future call to \c mono_error_set_from_boxed as needed. The
  730. * \p oerror should've been previously initialized with \c mono_error_init,
  731. * as usual.
  732. * \returns TRUE on success or FALSE on failure.
  733. */
  734. gboolean
  735. mono_error_set_from_boxed (MonoError *oerror, const MonoErrorBoxed *box)
  736. {
  737. MonoErrorInternal* to = (MonoErrorInternal*)oerror;
  738. MonoErrorInternal* from = (MonoErrorInternal*)&box->error;
  739. g_assert (!is_managed_exception (from));
  740. mono_error_prepare (to);
  741. to->flags |= MONO_ERROR_FREE_STRINGS;
  742. #define DUP_STR(field) do { \
  743. if (from->field) { \
  744. if (!(to->field = g_strdup (from->field))) \
  745. to->flags |= MONO_ERROR_INCOMPLETE; \
  746. } else { \
  747. to->field = NULL; \
  748. } \
  749. } while (0)
  750. to->error_code = from->error_code;
  751. DUP_STR (type_name);
  752. DUP_STR (assembly_name);
  753. DUP_STR (member_name);
  754. DUP_STR (exception_name_space);
  755. DUP_STR (exception_name);
  756. DUP_STR (full_message);
  757. DUP_STR (full_message_with_fields);
  758. DUP_STR (first_argument);
  759. to->exn.klass = from->exn.klass;
  760. #undef DUP_STR
  761. return (to->flags & MONO_ERROR_INCOMPLETE) == 0 ;
  762. }
  763. void
  764. mono_error_set_first_argument (MonoError *oerror, const char *first_argument)
  765. {
  766. MonoErrorInternal* to = (MonoErrorInternal*)oerror;
  767. to->first_argument = g_strdup (first_argument);
  768. to->flags |= MONO_ERROR_FREE_STRINGS;
  769. }