|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
//
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
}
}
|