summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Reflection/LoaderAllocator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Reflection/LoaderAllocator.cs')
-rw-r--r--src/mscorlib/src/System/Reflection/LoaderAllocator.cs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Reflection/LoaderAllocator.cs b/src/mscorlib/src/System/Reflection/LoaderAllocator.cs
new file mode 100644
index 0000000000..a8b4b0c3a0
--- /dev/null
+++ b/src/mscorlib/src/System/Reflection/LoaderAllocator.cs
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Security;
+using System.Collections.Generic;
+
+
+namespace System.Reflection
+{
+ //
+ // We can destroy the unmanaged part of collectible type only after the managed part is definitely gone and thus
+ // nobody can call/allocate/reference anything related to the collectible assembly anymore. A call to finalizer
+ // alone does not guarantee that the managed part is gone. A malicious code can keep a reference to some object
+ // in a way that that survives finalization, or we can be running during shutdown where everything is finalized.
+ //
+ // The unmanaged LoaderAllocator keeps a reference to the managed LoaderAllocator in long weak handle. If the long
+ // weak handle is null, we can be sure that the managed part of the LoaderAllocator is definitely gone and that it
+ // is safe to destroy the unmanaged part. Unfortunately, we can not perform the above check in a finalizer on the
+ // LoaderAllocator, but it can be performed on a helper object.
+ //
+ // The finalization does not have to be done using CriticalFinalizerObject. We have to go over all LoaderAllocators
+ // during AppDomain shutdown anyway to avoid leaks e.g. if somebody stores reference to LoaderAllocator in a static.
+ //
+ internal sealed class LoaderAllocatorScout
+ {
+ // This field is set by the VM to atomically transfer the ownership to the managed loader allocator
+ internal IntPtr m_nativeLoaderAllocator;
+
+ [SuppressUnmanagedCodeSecurity]
+ [SecurityCritical]
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ private static extern bool Destroy(IntPtr nativeLoaderAllocator);
+
+ [SecuritySafeCritical]
+ ~LoaderAllocatorScout()
+ {
+ if (m_nativeLoaderAllocator.IsNull())
+ return;
+
+ // Assemblies and LoaderAllocators will be cleaned up during AppDomain shutdown in
+ // unmanaged code
+ // So it is ok to skip reregistration and cleanup for finalization during appdomain shutdown.
+ // We also avoid early finalization of LoaderAllocatorScout due to AD unload when the object was inside DelayedFinalizationList.
+ if (!Environment.HasShutdownStarted &&
+ !AppDomain.CurrentDomain.IsFinalizingForUnload())
+ {
+
+ // Destroy returns false if the managed LoaderAllocator is still alive.
+ if (!Destroy(m_nativeLoaderAllocator))
+ {
+ // Somebody might have been holding a reference on us via weak handle.
+ // We will keep trying. It will be hopefully released eventually.
+ GC.ReRegisterForFinalize(this);
+ }
+ }
+ }
+ }
+
+ internal sealed class LoaderAllocator
+ {
+ LoaderAllocator()
+ {
+ m_slots = new object [5];
+ // m_slotsUsed = 0;
+
+ m_scout = new LoaderAllocatorScout();
+ }
+
+#pragma warning disable 169
+#pragma warning disable 414
+ LoaderAllocatorScout m_scout;
+ object [] m_slots;
+ internal CerHashtable<RuntimeMethodInfo, RuntimeMethodInfo> m_methodInstantiations;
+ int m_slotsUsed;
+#pragma warning restore 414
+#pragma warning restore 169
+ }
+}
+