InternalThread is a fundamentally different type WRT to appdomain. All instances of Thread bound to the same
os thread have a reference to a shared InternalThread.
InternalThread is always allocated in the root domain, so it MUST NOT have references to other domains as
it will lead to crashes on unload.
This was the case with pending_exception. It could point to an exception meant to the domain unloading.
This bug became more and more frequent as we move to use mono_set_pending_exception in more places. I could
reproduce it in 10 minutes of looping appdomain-unload.exe.
/* current System.Runtime.Remoting.Contexts.Context instance
keep as an object to avoid triggering its class constructor when not needed */
private object current_appcontext;
- private object pending_exception;
private object root_domain_thread;
internal byte[] _serialized_principal;
internal int _serialized_principal_version;
#region Sync with metadata/object-internals.h
private InternalThread internal_thread;
object m_ThreadStartArg;
+ object pending_exception;
#endregion
#pragma warning restore 414
* of icalls, do not require an increment.
*/
#pragma warning disable 169
- private const int mono_corlib_version = 140;
+ private const int mono_corlib_version = 141;
#pragma warning restore 169
[ComVisible (true)]
* Changes which are already detected at runtime, like the addition
* of icalls, do not require an increment.
*/
-#define MONO_CORLIB_VERSION 140
+#define MONO_CORLIB_VERSION 141
typedef struct
{
gpointer *static_data;
void *thread_info; /*This is MonoThreadInfo*, but to simplify dependencies, let's make it a void* here. */
MonoAppContext *current_appcontext;
- MonoException *pending_exception;
MonoThread *root_domain_thread;
MonoObject *_serialized_principal;
int _serialized_principal_version;
MonoObject obj;
struct _MonoInternalThread *internal_thread;
MonoObject *start_obj;
+ MonoException *pending_exception;
};
typedef struct {
mono_thread_execute_interruption (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *sys_thread = mono_thread_current ();
LOCK_THREAD (thread);
mono_thread_exit ();
return NULL;
- } else if (thread->pending_exception) {
+ } else if (sys_thread->pending_exception) {
MonoException *exc;
- exc = thread->pending_exception;
- thread->pending_exception = NULL;
+ exc = sys_thread->pending_exception;
+ sys_thread->pending_exception = NULL;
UNLOCK_THREAD (thread);
return exc;
mono_thread_get_and_clear_pending_exception (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *sys_thread = mono_thread_current ();
/* The thread may already be stopping */
if (thread == NULL)
return mono_thread_execute_interruption ();
}
- if (thread->pending_exception) {
- MonoException *exc = thread->pending_exception;
+ if (sys_thread->pending_exception) {
+ MonoException *exc = sys_thread->pending_exception;
- thread->pending_exception = NULL;
+ sys_thread->pending_exception = NULL;
return exc;
}
void
mono_set_pending_exception (MonoException *exc)
{
- MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *thread = mono_thread_current ();
/* The thread may already be stopping */
if (thread == NULL)