File: System\Reflection\TypeLoading\General\Ecma\GuardedPEReader.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
 
namespace System.Reflection.TypeLoading.Ecma
{
    //
    // Accessing MetadataReaders after their containing PEReaders have been disposed fails in very messy ways
    // (as in accessing native memory after free.) This also crashes debugged processes if Reflection objects
    // created by MetadataLoadContext objects are sitting in the watch window after disposal.
    //
    // To avoid this unfortunate scenario, we'll gate all access to PEReaders and MetadataReaders
    // through this dispose guard. This does not make the api entirely safe (if a Reflection api is in flight
    // during a Dispose(), all bets are off) but it does make the overall experience less evil.
    //
    internal readonly struct GuardedPEReader
    {
        private readonly MetadataLoadContext _loader;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] // Don't want debugger watch windows triggering AV's if one is still around after disposal.
        private readonly PEReader _peReader;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] // Don't want debugger watch windows triggering AV's if one is still around after disposal.
        private readonly MetadataReader _reader;
 
        public GuardedPEReader(MetadataLoadContext loader, PEReader peReader, MetadataReader reader)
        {
            Debug.Assert(loader != null);
            Debug.Assert(peReader != null);
            Debug.Assert(reader != null);
 
            _loader = loader;
            _peReader = peReader;
            _reader = reader;
        }
 
        public PEReader PEReader { get { _loader.DisposeCheck(); return _peReader; } }
        public MetadataReader Reader { get { _loader.DisposeCheck(); return _reader; } }
    }
}