Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
authormonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 9 Jun 2016 16:55:12 +0000 (17:55 +0100)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 9 Jun 2016 16:55:12 +0000 (17:55 +0100)
Using mono_marshal_free n mono_string_builder_to_utf8

`mono_string_builder_to_utf16` is allocating using `mono_marshal_alloc` which, on windows, allocates memory using `CoTaskMemAlloc`. This buffer was then released in `mono_string_builder_to_utf8` using `g_free` which resulted in a crash since that's a different memory on windows. The fix in this PR makes sure `mono_marshal_free` is called instead which has the correct behaviour and results in a `CoTaskMemFree` on windows.

1  2 
mono/metadata/marshal.c

diff --combined mono/metadata/marshal.c
index 86e66ece626ce9a7560ea03a47cf58d44222bf69,923cc99831b4e0e64eb85371adf85cef5b94c481..2b3eea28a151551d82226202078524a6b435e4a3
@@@ -45,7 -45,6 +45,7 @@@
  #include "mono/utils/mono-memory-model.h"
  #include "mono/utils/atomic.h"
  #include <mono/utils/mono-threads.h>
 +#include <mono/utils/mono-threads-coop.h>
  #include <mono/utils/mono-error-internals.h>
  
  #include <string.h>
@@@ -80,16 -79,11 +80,16 @@@ static MonoNativeTlsKey load_type_info_
  
  static gboolean use_aot_wrappers;
  
 -static MonoFtnPtrEHCallback ftnptr_eh_callback;
 +static void ftnptr_eh_callback_default (guint32 gchandle);
 +
 +static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default;
  
  static void
  delegate_hash_table_add (MonoDelegate *d);
  
 +static void
 +delegate_hash_table_remove (MonoDelegate *d);
 +
  static void
  emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
  
@@@ -200,6 -194,9 +200,6 @@@ mono_array_to_lparray (MonoArray *array
  void
  mono_free_lparray (MonoArray *array, gpointer* nativeArray);
  
 -static gint32
 -mono_marshal_has_ftnptr_eh_callback (void);
 -
  static void
  mono_marshal_ftnptr_eh_callback (guint32 gchandle);
  
@@@ -258,24 -255,6 +258,24 @@@ mono_object_isinst_icall (MonoObject *o
        return result;
  }
  
 +static MonoString*
 +ves_icall_mono_string_from_utf16 (gunichar2 *data)
 +{
 +      MonoError error;
 +      MonoString *result = mono_string_from_utf16_checked (data, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
 +
 +static char*
 +ves_icall_mono_string_to_utf8 (MonoString *str)
 +{
 +      MonoError error;
 +      char *result = mono_string_to_utf8_checked (str, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
 +
  void
  mono_marshal_init (void)
  {
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
                register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
                register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
 -              register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
 +              register_icall (ves_icall_mono_string_from_utf16, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE);
                register_icall (mono_string_from_byvalstr, "mono_string_from_byvalstr", "obj ptr int", FALSE);
                register_icall (mono_string_from_byvalwstr, "mono_string_from_byvalwstr", "obj ptr int", FALSE);
                register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
                register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
 -              register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
 +              register_icall (ves_icall_mono_string_to_utf8, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE);
                register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
                register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
                register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
                register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
                register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
 -              register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
                register_icall (mono_context_get, "mono_context_get", "object", FALSE);
                register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
                register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
                register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
                register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
                register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
 -              register_icall (mono_marshal_has_ftnptr_eh_callback, "mono_marshal_has_ftnptr_eh_callback", "int32", TRUE);
                register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
 +              register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
 +              register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
 +              register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
 +              register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
  
                mono_cominterop_init ();
                mono_remoting_init ();
 -
 -              if (mono_threads_is_coop_enabled ()) {
 -                      register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "ptr ptr", TRUE);
 -                      register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void ptr ptr", TRUE);
 -                      register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","ptr ptr", TRUE);
 -                      register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void ptr ptr", TRUE);
 -              }
        }
  }
  
@@@ -409,22 -393,19 +409,22 @@@ mono_delegate_to_ftnptr (MonoDelegate *
  
        wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
  
 -      delegate->delegate_trampoline = mono_compile_method (wrapper);
 +      delegate->delegate_trampoline = mono_compile_method_checked (wrapper, &error);
 +      if (!is_ok (&error))
 +              goto fail;
  
        // Add the delegate to the delegate hash table
        delegate_hash_table_add (delegate);
  
        /* when the object is collected, collect the dynamic method, too */
 -      mono_object_register_finalizer ((MonoObject*)delegate, &error);
 -      if (!mono_error_ok (&error)) {
 -              mono_error_set_pending_exception (&error);
 -              return NULL;
 -      }
 +      mono_object_register_finalizer ((MonoObject*)delegate);
  
        return delegate->delegate_trampoline;
 +
 +fail:
 +      mono_gchandle_free (target_handle);
 +      mono_error_set_pending_exception (&error);
 +      return NULL;
  }
  
  /* 
@@@ -589,12 -570,7 +589,12 @@@ mono_ftnptr_to_delegate (MonoClass *kla
                        mono_error_set_pending_exception (&error);
                        return NULL;
                }
 -              mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
 +              gpointer compiled_ptr = mono_compile_method_checked (wrapper, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
 +              mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, compiled_ptr, wrapper, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        }
  
        if (d->object.vtable->domain != mono_domain_get ()) {
@@@ -962,7 -938,7 +962,7 @@@ mono_string_utf16_to_builder (MonoStrin
   *
   * Returns: a utf8 string with the contents of the StringBuilder.
   *
-  * The return value must be released with g_free.
+  * The return value must be released with mono_marshal_free.
   *
   * This is a JIT icall, it sets the pending exception and returns NULL on error.
   */
@@@ -983,14 -959,14 +983,14 @@@ mono_string_builder_to_utf8 (MonoString
  
        if (gerror) {
                g_error_free (gerror);
-               g_free (str_utf16);
+               mono_marshal_free (str_utf16);
                mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
                return NULL;
        } else {
                guint len = mono_string_builder_capacity (sb) + 1;
                gchar *res = (gchar *)mono_marshal_alloc (len * sizeof (gchar), &error);
                if (!mono_error_ok (&error)) {
-                       g_free (str_utf16);
+                       mono_marshal_free (str_utf16);
                        g_free (tmp);
                        mono_error_set_pending_exception (&error);
                        return NULL;
                memcpy (res, tmp, str_len * sizeof (gchar));
                res[str_len] = '\0';
  
-               g_free (str_utf16);
+               mono_marshal_free (str_utf16);
                g_free (tmp);
                return res;
        }
   *
   * Returns: a utf16 string with the contents of the StringBuilder.
   *
-  * The return value must not be freed.
+  * The return value must be released with mono_marshal_free.
+  *
   * This is a JIT icall, it sets the pending exception and returns NULL on error.
   */
  gunichar2*
@@@ -1094,10 -1071,7 +1095,10 @@@ mono_string_to_lpstr (MonoString *s
                return as;
        }
  #else
 -      return mono_string_to_utf8 (s);
 +      MonoError error;
 +      char *result = mono_string_to_utf8_checked (s, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
  #endif
  }     
  
@@@ -1120,7 -1094,6 +1121,7 @@@ mono_string_to_ansibstr (MonoString *st
  void
  mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
  {
 +      MonoError error;
        char *s;
        int len;
  
        if (!src)
                return;
  
 -      s = mono_string_to_utf8 (src);
 +      s = mono_string_to_utf8_checked (src, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return;
        len = MIN (size, strlen (s));
        if (len >= size)
                len--;
@@@ -1472,7 -1443,7 +1473,7 @@@ emit_ptr_to_object_conv (MonoMethodBuil
                } else {
                        mono_mb_emit_ldloc (mb, 1);
                        mono_mb_emit_ldloc (mb, 0);
 -                      mono_mb_emit_icall (mb, mono_string_from_utf16);
 +                      mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                }
                mono_mb_emit_byte (mb, CEE_STIND_REF);          
                break;          
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
  #ifdef TARGET_WIN32
 -              mono_mb_emit_icall (mb, mono_string_from_utf16);
 +              mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
  #else
                mono_mb_emit_icall (mb, mono_string_new_wrapper);
  #endif
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_icall (mb, mono_string_from_utf16);
 +              mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                mono_mb_emit_byte (mb, CEE_STIND_REF);
                break;
        case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
@@@ -1611,7 -1582,7 +1612,7 @@@ conv_to_icall (MonoMarshalConv conv, in
                return mono_marshal_string_to_utf16;            
        case MONO_MARSHAL_CONV_LPWSTR_STR:
                *ind_store_type = CEE_STIND_REF;
 -              return mono_string_from_utf16;
 +              return ves_icall_mono_string_from_utf16;
        case MONO_MARSHAL_CONV_LPTSTR_STR:
                *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
@@@ -2252,12 -2223,8 +2253,12 @@@ mono_delegate_begin_invoke (MonoDelegat
                        MonoArray *out_args;
                        method = delegate->method;
  
 -                      msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
 -                      ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL);
 +                      msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state, &error);
 +                      if (mono_error_set_pending_exception (&error))
 +                              return NULL;
 +                      ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL, &error);
 +                      if (mono_error_set_pending_exception (&error))
 +                              return NULL;
                        MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
                        MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
                        MONO_OBJECT_SETREF (msg, async_result, ares);
@@@ -2984,9 -2951,7 +2985,9 @@@ mono_delegate_end_invoke (MonoDelegate 
  
        sig = mono_signature_no_pinvoke (method);
  
 -      msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
 +      msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return NULL;
  
        ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
        if (ares == NULL) {
                        mono_error_set_pending_exception (&error);
                        return NULL;
                }
 -              mono_message_init (domain, msg, delegate->method_info, NULL);
 +              mono_message_init (domain, msg, delegate->method_info, NULL, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
                msg->call_type = CallType_EndInvoke;
                MONO_OBJECT_SETREF (msg, async_result, ares);
                res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
        } else
  #endif
        {
 -              res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc);
 +              res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        }
  
        if (exc) {
                if (((MonoException*)exc)->stack_trace) {
 -                      char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
 -                      char  *tmp;
 -                      tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
 -                      g_free (strace);        
 -                      MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
 -                      g_free (tmp);
 +                      MonoError inner_error;
 +                      char *strace = mono_string_to_utf8_checked (((MonoException*)exc)->stack_trace, &inner_error);
 +                      if (is_ok (&inner_error)) {
 +                              char  *tmp;
 +                              tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
 +                              g_free (strace);        
 +                              MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
 +                              g_free (tmp);
 +                      } else
 +                              mono_error_cleanup (&inner_error); /* no stack trace, but at least throw the original exception */
                }
                mono_set_pending_exception ((MonoException*)exc);
        }
@@@ -7322,9 -7279,12 +7323,9 @@@ mono_marshal_emit_native_wrapper (MonoI
        EmitMarshalContext m;
        MonoMethodSignature *csig;
        MonoClass *klass;
 -      MonoExceptionClause *clause;
        int i, argnum, *tmp_locals;
        int type, param_shift = 0;
 -      static MonoMethodSignature *get_last_error_sig = NULL;
 -      int coop_gc_stack_dummy, coop_gc_var, coop_unblocked_var;
 -      int leave_pos;
 +      int coop_gc_stack_dummy, coop_gc_var;
  
        memset (&m, 0, sizeof (m));
        m.mb = mb;
                coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                /* local 5, the local to be used when calling the suspend funcs */
                coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -              coop_unblocked_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -
 -              clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
 -              clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
        }
  
 +      /*
 +       * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
 +       *
 +       * ret = method (...);
 +       *
 +       * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
 +       *
 +       * <interrupt check>
 +       *
 +       * return ret;
 +       */
 +
        if (MONO_TYPE_ISSTRUCT (sig->ret))
                m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  
                        mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
                }
  
 -              clause->try_offset = mono_mb_get_label (mb);
 -
                mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 -              mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
 +              mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
                mono_mb_emit_stloc (mb, coop_gc_var);
        }
  
  #else
                g_assert_not_reached ();
  #endif
 -      }
 -      else {
 +      } else {
                if (aot) {
                        /* Reuse the ICALL_ADDR opcode for pinvokes too */
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                }
        }
  
 -      if (MONO_TYPE_ISSTRUCT (sig->ret)) {
 -              MonoClass *klass = mono_class_from_mono_type (sig->ret);
 -              mono_class_init (klass);
 -              if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
 -                      /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
 -                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -                      mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 -                      mono_mb_emit_stloc (mb, m.vtaddr_var);
 -              }
 -      }
 -
 -      /* Unblock before converting the result, since that can involve calls into the runtime */
 -      if (mono_threads_is_coop_enabled ()) {
 -              mono_mb_emit_ldloc (mb, coop_gc_var);
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 -              mono_mb_emit_icall (mb, mono_threads_finish_blocking);
 -              mono_mb_emit_icon (mb, 1);
 -              mono_mb_emit_stloc (mb, coop_unblocked_var);
 -      }
 -
        /* Set LastError if needed */
        if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
 +#ifdef TARGET_WIN32
 +              static MonoMethodSignature *get_last_error_sig = NULL;
                if (!get_last_error_sig) {
                        get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
                        get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
                        get_last_error_sig->pinvoke = 1;
                }
  
 -#ifdef TARGET_WIN32
                /*
                 * Have to call GetLastError () early and without a wrapper, since various runtime components could
                 * clobber its value.
  #endif
        }
  
 +      if (MONO_TYPE_ISSTRUCT (sig->ret)) {
 +              MonoClass *klass = mono_class_from_mono_type (sig->ret);
 +              mono_class_init (klass);
 +              if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
 +                      /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 +                      mono_mb_emit_stloc (mb, m.vtaddr_var);
 +              }
 +      }
 +
 +      /* Unblock before converting the result, since that can involve calls into the runtime */
 +      if (mono_threads_is_coop_enabled ()) {
 +              mono_mb_emit_ldloc (mb, coop_gc_var);
 +              mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 +              mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
 +      }
 +
        /* convert the result */
        if (!sig->ret->byref) {
                MonoMarshalSpec *spec = mspecs [0];
                mono_mb_emit_stloc (mb, 3);
        }
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              int pos;
 -
 -              leave_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
 -
 -              clause->try_len = mono_mb_get_label (mb) - clause->try_offset;
 -              clause->handler_offset = mono_mb_get_label (mb);
 -
 -              mono_mb_emit_ldloc (mb, coop_unblocked_var);
 -              mono_mb_emit_icon (mb, 1);
 -              pos = mono_mb_emit_branch (mb, CEE_BEQ);
 -
 -              mono_mb_emit_ldloc (mb, coop_gc_var);
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 -              mono_mb_emit_icall (mb, mono_threads_finish_blocking);
 -
 -              mono_mb_patch_branch (mb, pos);
 -
 -              mono_mb_emit_byte (mb, CEE_ENDFINALLY);
 -
 -              clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
 -
 -              mono_mb_patch_branch (mb, leave_pos);
 -      }
 -
        /* 
         * Need to call this after converting the result since MONO_VTADDR needs 
         * to be adjacent to the call instruction.
                mono_mb_emit_ldloc (mb, 3);
  
        mono_mb_emit_byte (mb, CEE_RET);
 -
 -      if (mono_threads_is_coop_enabled ()) {
 -              mono_mb_set_clauses (mb, 1, clause);
 -      }
  }
  #endif /* DISABLE_JIT */
  
@@@ -7985,8 -7970,8 +7986,8 @@@ mono_marshal_emit_managed_wrapper (Mono
  #else
        MonoMethodSignature *sig, *csig;
        MonoExceptionClause *clauses, *clause_finally, *clause_catch;
 -      int i, *tmp_locals, ex_local, e_local;
 -      int leave_try_pos, leave_catch_pos, ex_m1_pos, rethrow_pos;
 +      int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
 +      int leave_try_pos, leave_catch_pos, ex_m1_pos;
        gboolean closed = FALSE;
  
        sig = m->sig;
        ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
        e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
  
 +      attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 +      attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 +
        /*
         * guint32 ex = -1;
         * try {
 -       *   mono_jit_attach ();
 +       *   // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
 +       *   mono_threads_attach_coop ();
         *
         *   <interrupt check>
         *
         *   ret = method (...);
         * } catch (Exception e) {
 -       *   if (!mono_marshal_has_ftnptr_eh_callback ())
 -       *     throw e;
         *   ex = mono_gchandle_new (e, false);
         * } finally {
 -       *   mono_jit_detach ();
 +       *   // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
 +       *   mono_threads_detach_coop ();
 +       *
 +       *   if (ex != -1)
 +       *     mono_marshal_ftnptr_eh_callback (ex);
         * }
 -       * if (ex != -1)
 -       *   mono_marshal_ftnptr_eh_callback (ex);
         *
         * return ret;
         */
        /* try { */
        clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
  
 -      /*
 -       * Might need to attach the thread to the JIT or change the
 -       * domain for the callback.
 -       *
 -       * Also does the (STARTING|BLOCKING|RUNNING) -> RUNNING thread state transtion
 -       *
 -       * mono_jit_attach ();
 -       */
 -      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -      mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
 +      if (!mono_threads_is_coop_enabled ()) {
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
 +      } else {
 +              /* mono_threads_attach_coop (); */
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
 +              mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
 +              mono_mb_emit_icall (mb, mono_threads_attach_coop);
 +              mono_mb_emit_stloc (mb, attach_cookie_local);
 +      }
  
        /* <interrupt check> */
        emit_thread_interrupt_checkpoint (mb);
  
        leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
  
 -      /* } catch (Exception e) { */
 +      /* } [endtry] */
 +
 +      /* catch (Exception e) { */
        clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
        clause_catch->handler_offset = mono_mb_get_label (mb);
  
        mono_mb_emit_stloc (mb, e_local);
  
 -      /* if (!mono_marshal_has_ftnptr_eh_callback ()) { */
 -      mono_mb_emit_icall (mb, mono_marshal_has_ftnptr_eh_callback);
 -      rethrow_pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
 -
 -      /* throw e; */
 -      mono_mb_emit_ldloc (mb, e_local);
 -      mono_mb_emit_byte (mb, CEE_THROW);
 -
 -      /* } [endif] */
 -      mono_mb_patch_branch (mb, rethrow_pos);
 -
        /* ex = mono_gchandle_new (e, false); */
        mono_mb_emit_ldloc (mb, e_local);
        mono_mb_emit_icon (mb, 0);
        /* } [endcatch] */
        clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
  
 -      /* finally { */
 +      /* finally { */
        clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
        clause_finally->handler_offset = mono_mb_get_label (mb);
  
 -      /*
 -       * Also does the RUNNING -> (BLOCKING|RUNNING) thread state transition
 -       *
 -       * mono_jit_detach ();
 -       */
 -      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -      mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
 -
 -      mono_mb_emit_byte (mb, CEE_ENDFINALLY);
 -
 -      /* } [endfinally] */
 -      clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
 -
 -      mono_mb_patch_branch (mb, leave_try_pos);
 -      mono_mb_patch_branch (mb, leave_catch_pos);
 +      if (!mono_threads_is_coop_enabled ()) {
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
 +      } else {
 +              /* mono_threads_detach_coop (); */
 +              mono_mb_emit_ldloc (mb, attach_cookie_local);
 +              mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
 +              mono_mb_emit_icall (mb, mono_threads_detach_coop);
 +      }
  
        /* if (ex != -1) */
        mono_mb_emit_ldloc (mb, ex_local);
        /* [ex == -1] */
        mono_mb_patch_branch (mb, ex_m1_pos);
  
 +      mono_mb_emit_byte (mb, CEE_ENDFINALLY);
 +
 +      /* } [endfinally] */
 +      clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
 +
 +      mono_mb_patch_branch (mb, leave_try_pos);
 +      mono_mb_patch_branch (mb, leave_catch_pos);
 +
        /* return ret; */
        if (m->retobj_var) {
                mono_mb_emit_ldloc (mb, m->retobj_var);
@@@ -8551,9 -8538,7 +8552,9 @@@ mono_marshal_get_vtfixup_ftnptr (MonoIm
                                mono_metadata_free_marshal_spec (mspecs [i]);
                g_free (mspecs);
  
 -              return mono_compile_method (method);
 +              gpointer compiled_ptr = mono_compile_method_checked (method, &error);
 +              mono_error_assert_ok (&error);
 +              return compiled_ptr;
        }
  
        sig = mono_method_signature (method);
        method = mono_mb_create (mb, sig, param_count, NULL);
        mono_mb_free (mb);
  
 -      return mono_compile_method (method);
 +      gpointer compiled_ptr = mono_compile_method_checked (method, &error);
 +      mono_error_assert_ok (&error);
 +      return compiled_ptr;
  }
  
  #ifndef DISABLE_JIT
@@@ -8709,14 -8692,12 +8710,14 @@@ mono_marshal_get_castclass_with_cache (
        return cached;
  }
  
 +/* this is an icall */
  static MonoObject *
  mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
  {
        MonoError error;
        MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
 -      mono_error_raise_exception (&error); /* FIXME don't raise here */
 +      if (mono_error_set_pending_exception (&error))
 +              return NULL;
  
  #ifndef DISABLE_REMOTING
        if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
@@@ -10794,7 -10775,6 +10795,7 @@@ ves_icall_System_Runtime_InteropService
  int
  ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
  {
 +      MonoError error;
        MonoMarshalType *info;
        MonoClass *klass;
        char *fname;
        MONO_CHECK_ARG_NULL (type, 0);
        MONO_CHECK_ARG_NULL (field_name, 0);
  
 -      fname = mono_string_to_utf8 (field_name);
 +      fname = mono_string_to_utf8_checked (field_name, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return 0;
        klass = mono_class_from_mono_type (type->type);
        if (!mono_class_init (klass)) {
                mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
  gpointer
  ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
  {
 +      MonoError error;
  #ifdef HOST_WIN32
        char* tres, *ret;
        size_t len;
 -      tres = mono_string_to_utf8 (string);
 +      tres = mono_string_to_utf8_checked (string, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return NULL;
        if (!tres)
                return tres;
  
        return ret;
  
  #else
 -      return mono_string_to_utf8 (string);
 +      char *ret = mono_string_to_utf8_checked (string, &error);
 +      mono_error_set_pending_exception (&error);
 +      return ret;
  #endif
  }
  
@@@ -11720,12 -11693,10 +11721,12 @@@ mono_marshal_get_thunk_invoke_wrapper (
        GHashTable *cache;
        MonoMethod *res;
        int i, param_count, sig_size, pos_leave;
 -      int coop_gc_var, coop_gc_dummy_local;
  
        g_assert (method);
  
 +      // FIXME: we need to store the exception into a MonoHandle
 +      g_assert (!mono_threads_is_coop_enabled ());
 +
        klass = method->klass;
        image = method->klass->image;
  
        if (!MONO_TYPE_IS_VOID (sig->ret))
                mono_mb_add_local (mb, sig->ret);
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* local 4, the local to be used when calling the reset_blocking funcs */
 -              /* tons of code hardcode 3 to be the return var */
 -              coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -              /* local 5, the local used to get a stack address for suspend funcs */
 -              coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -      }
 -
        /* clear exception arg */
        mono_mb_emit_ldarg (mb, param_count - 1);
        mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_STIND_REF);
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* FIXME this is technically wrong as the callback itself must be executed in gc unsafe context. */
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
 -              mono_mb_emit_stloc (mb, coop_gc_var);
 -      }
 -
        /* try */
        clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
        clause->try_offset = mono_mb_get_label (mb);
                        mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
        }
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* XXX merge reset_blocking_end with detach */
 -              mono_mb_emit_ldloc (mb, coop_gc_var);
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
 -      }
 -
        mono_mb_emit_byte (mb, CEE_RET);
  #endif
  
@@@ -11889,6 -11882,12 +11890,6 @@@ mono_marshal_free_dynamic_wrappers (Mon
                mono_marshal_unlock ();
  }
  
 -static gint32
 -mono_marshal_has_ftnptr_eh_callback (void)
 -{
 -      return ftnptr_eh_callback != NULL;
 -}
 -
  static void
  mono_marshal_ftnptr_eh_callback (guint32 gchandle)
  {
        ftnptr_eh_callback (gchandle);
  }
  
 +static void
 +ftnptr_eh_callback_default (guint32 gchandle)
 +{
 +      MonoException *exc;
 +      gpointer stackdata;
 +
 +      g_assert (gchandle >= 0);
 +
 +      mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata);
 +
 +      exc = (MonoException*) mono_gchandle_get_target (gchandle);
 +
 +      mono_gchandle_free (gchandle);
 +
 +      mono_raise_exception (exc);
 +}
 +
  /*
   * mono_install_ftnptr_eh_callback:
   *