[metadata] Lock around special static fields hash access
authorVlad Brezae <brezaevlad@gmail.com>
Thu, 20 Apr 2017 12:01:30 +0000 (15:01 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Fri, 21 Apr 2017 23:30:23 +0000 (02:30 +0300)
If a type is loaded in another thread, the fields hash can get resized, leading to failure.

mono/mini/jit-icalls.c
mono/tests/Makefile.am
mono/tests/generic-special2.2.cs [new file with mode: 0644]

index b52edd4e404bf1fadba2233bdb25834d92dcf840..401ac247e2a0569fb100aa530f9df08cb1682c03 100644 (file)
@@ -888,11 +888,16 @@ mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
 
        //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
 
-       if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
+       if (field->offset == -1) {
+               /* Special static */
+               g_assert (domain->special_static_fields);
+               mono_domain_lock (domain);
+               addr = g_hash_table_lookup (domain->special_static_fields, field);
+               mono_domain_unlock (domain);
                addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
-       else
+       } else {
                addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
-       
+       }
        return addr;
 }
 
index 6b38d8d7e4bba9b3e3a299178a59963f1316acd1..10741f6d57c6c8dba7faac48d79f513333b58b90 100644 (file)
@@ -344,6 +344,7 @@ TESTS_CS_SRC=               \
        generic-static-methods.2.cs     \
        generic-null-call.2.cs  \
        generic-special.2.cs    \
+       generic-special2.2.cs   \
        generic-exceptions.2.cs \
        generic-virtual2.2.cs   \
        generic-valuetype-interface.2.cs        \
@@ -616,6 +617,7 @@ TESTS_GSHARED_SRC = \
        generic-tailcall2.2.cs                  \
        generic-array-exc.2.cs  \
        generic-special.2.cs                    \
+       generic-special2.2.cs   \
        generic-exceptions.2.cs \
        generic-delegate2.2.cs          \
        generic-virtual2.2.cs   \
diff --git a/mono/tests/generic-special2.2.cs b/mono/tests/generic-special2.2.cs
new file mode 100644 (file)
index 0000000..625d873
--- /dev/null
@@ -0,0 +1,54 @@
+using System;
+using System.Reflection;
+using System.IO;
+using System.Collections.Generic;
+using System.Threading;
+
+internal class GenericType<T> {
+       [ThreadStatic]
+       internal static object static_var;
+
+       public static void AccessStaticVar ()
+       {
+               if (static_var != null && static_var.GetType () != typeof (List<T>))
+                       throw new Exception ("Corrupted static var");
+               GenericType<T>.static_var = new List<T> ();
+       }
+}
+
+public static class Program {
+       private static bool stress;
+
+       /* Create a lot of static vars */
+       private static void CreateVTables ()
+       {
+               Type[] nullArgs = new Type[0];
+               Assembly ass = Assembly.GetAssembly (typeof (int));
+               foreach (Type type in ass.GetTypes ()) {
+                       try {
+                               Type inst = typeof (GenericType<>).MakeGenericType (type);
+                               Activator.CreateInstance (inst);
+                       } catch {
+                       }
+               }
+       }
+
+       private static void StressStaticFieldAddr ()
+       {
+               while (stress) {
+                       GenericType<object>.AccessStaticVar ();
+               }
+       }
+
+       public static void Main (string[] args)
+       {
+               Thread thread = new Thread (StressStaticFieldAddr);
+
+               stress = true;
+               thread.Start ();
+               CreateVTables ();
+               stress = false;
+
+               thread.Join ();
+       }
+}