Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Reflection.Metadata throws OOM on corrupt custom attribute value (mega array) #57531

Closed
joelverhagen opened this issue Aug 16, 2021 · 13 comments

Comments

@joelverhagen
Copy link
Member

Description

I am using the System.Reflection.Metadata package to analyze all custom assembly attributes on NuGet.org. I am running into several strange DLLs that cause my code to OOM and I have traced it down to this line:

var array = ImmutableArray.CreateBuilder<CustomAttributeTypedArgument<TType>>(count);

For some nasty DLLs, this count is, for example, 1,868,786,036 which causes an OOM (OutOfMemoryException) on Azure Functions. This code will inevitably throw a BadImageFormatException on the subsequent for loop (there are not actually this many items in the array).

Ideally, there would be a way to detect this problem prior to allocating the array or provide a hook (perhaps in the ICustomAttributeTypeProvider<TType>) to mitigate this problem. On machines that happen to have enough memory for these mega allocations, I can catch BadImageFormatException. IMHO this exception is a good signal for such a problem.

On machines where OutOfMemoryException is thrown, I am using a workaround that catches OutOfMemoryException, if and only if ICustomAttributeTypeProvider.GetSZArrayType has been invoked at least once (I do this with a stateful counter in the provider implementation). Personally, I try to avoid blanket OOM catches in my code since OOMs can happen for a million different reasons.

Perhaps we can avoid the pre-allocation on the ImmutableArray builder if count is greater than some fuzz factor (e.g. 1024)? I don't have the data yet but it seems unlikely for have many thousands of elements in a custom attribute array argument.

One example DLL with this is on NuGet.org: Kentico.Xperience.AspNet.Mvc5.Libraries 13.0.18 at path lib/NET48/Kentico.Content.Web.Mvc.dll.

Configuration

  • Which version of .NET is the code running on? 6.0.100-preview.7.21379
  • What OS and version, and what distro if applicable? Windows 10.0.19042
  • What is the architecture (x64, x86, ARM, ARM64)? x64
  • Do you know whether it is specific to that configuration? I don't believe it is

The version I am using is System.Reflection.Metadata 5.0.0.

Regression?

No

Other information

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Reflection.Metadata untriaged New issue has not been triaged by the area owner labels Aug 16, 2021
@ghost ghost added this to Needs triage in Triage POD for Meta, Reflection, etc Aug 16, 2021
@MichalStrehovsky
Copy link
Member

Possibly related to #16724. We could also offer an API shape that doesn't require an allocation.

@joperezr
Copy link
Member

Thanks for the report @joelverhagen. @steveharter do you think we can fix the call to not allocate when count is obviously wrong? Or do you think we should instead porpose a new API that can perform the check so that we can detect (without allocating) if a dll is corrupt?

@joperezr joperezr added bug and removed untriaged New issue has not been triaged by the area owner labels Aug 17, 2021
@joperezr joperezr moved this from Needs triage to Future in Triage POD for Meta, Reflection, etc Aug 17, 2021
@steveharter
Copy link
Member

Thanks for the report @joelverhagen. @steveharter do you think we can fix the call to not allocate when count is obviously wrong? Or do you think we should instead porpose a new API that can perform the check so that we can detect (without allocating) if a dll is corrupt?

Planned steps:

  1. Verify the issue using Kentico.Content.Web.Mvc.dll
  2. Verify the metadata decoding is correct in MetadataLoadContext, and the problem is a corrupt assembly (how did it get this way?)
  3. Determine action from there:
    3a) If it is a corrupt assembly, consider using the internal ArrayBuilder<T> which will allocate dynamically. If we eventually get a BadImageFormatException later for other reasons, because the assembly is corrupt, this seems like a workable solution.

@steveharter
Copy link
Member

@joelverhagen do you have any other assemblies from NuGet handy that we can use for verification of a potential fix?

@steveharter
Copy link
Member

On step 2 above (verify correctness in decoding) also see #60579 which also has issues with DecodeArrayArgument.

@joelverhagen
Copy link
Member Author

@steveharter, there are over 3000 packages on NuGet.org (and 8000 contained assemblies) with this problem. Here are 100.

Identity Path EdgeCases
archy/1.0.3 tools/netcoreapp3.1/any/Microsoft.ML.Data.dll CustomAttributes_TruncatedAttributes, CustomAttributes_ArrayOutOfMemory
archy/1.0.3 tools/netcoreapp3.1/any/Microsoft.ML.KMeansClustering.dll CustomAttributes_ArrayOutOfMemory
archy/1.0.3 tools/netcoreapp3.1/any/Microsoft.ML.PCA.dll CustomAttributes_ArrayOutOfMemory
archy/1.0.3 tools/netcoreapp3.1/any/Microsoft.ML.StandardTrainers.dll CustomAttributes_ArrayOutOfMemory
archy/1.0.3 tools/netcoreapp3.1/any/Microsoft.ML.Transforms.dll CustomAttributes_ArrayOutOfMemory
clancey.comet.templates.multiplatform/0.3.416-beta single-project/CometApp1/bin/Debug/net6.0-maccatalyst/maccatalyst-x64/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet.templates.multiplatform/0.3.416-beta single-project/CometApp1/bin/Debug/net6.0-maccatalyst/maccatalyst-x64/CometApp1.app/Contents/MonoBundle/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet.templates.multiplatform/0.3.416-beta single-project/CometApp1/obj/Debug/net6.0-maccatalyst/maccatalyst-x64/linked/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.415-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.416-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.417-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.420-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.423-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.424-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.425-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.426-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.427-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.428-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.429-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.430-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/net6.0-android30.0/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/net6.0-ios13.6/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/net6.0-maccatalyst13.5/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/net6.0-windows10.0.19041/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/netstandard2.1/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.431-beta lib/xamarinios10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory
clancey.comet/0.3.432-beta lib/monoandroid10/Comet.dll CustomAttributes_MethodDefinition, CustomAttributes_ArrayOutOfMemory

@steveharter
Copy link
Member

@steveharter, there are over 3000 packages on NuGet.org (and 8000 contained assemblies) with this problem. Here are 100.

Thanks!

@steveharter steveharter self-assigned this Jul 14, 2022
@steveharter
Copy link
Member

@joelverhagen can you provide a minimal repro? I assume you have an implementation of ICustomAttributeTypeProvider that is relevant for the repro.

I first attempted to repro using MetadataLoadContext (since it layers on S.R.Metadata) and was able to enumerate all custom attributes on the Kentico.Content.Web.Mvc assembly and inspect all state - I made sure all assembly references were properly resolved since there are some attributes used from external assemblies including CMS*.

Then I attempted repro using MetadataReader directly and was able to enumerate all attributes successfully, but did not attempt to implement ICustomAttributeTypeProvider in order to do CustomAttribute.DecodeValue() since that is implementation-specific for resolving types etc.

@steveharter steveharter added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jul 14, 2022
@ghost
Copy link

ghost commented Jul 14, 2022

This issue has been marked needs-author-action and may be missing some important information.

@joelverhagen
Copy link
Member Author

joelverhagen commented Jul 14, 2022

@steveharter, here's a minimal repro. Pass a DLL path as a command line arg. It won't OOM on all PCs so I made the app halt when memory exceeds 1 GB.

repro
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;

var path = args[0];

using var fileStream = File.OpenRead(path);
using var peReader = new PEReader(fileStream);
var metadataReader = peReader.GetMetadataReader();

Console.WriteLine($"Reading {path}...");
Read(metadataReader);

static void Read(MetadataReader metadata)
{
    foreach (var customAttributeHandle in metadata.GetAssemblyDefinition().GetCustomAttributes())
    {
        var attribute = metadata.GetCustomAttribute(customAttributeHandle);
        string attributeName;
        if (attribute.Constructor.Kind == HandleKind.MemberReference)
        {
            var memberReference = metadata.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
            if (memberReference.Parent.Kind == HandleKind.TypeReference)
            {
                var typeReference = metadata.GetTypeReference((TypeReferenceHandle)memberReference.Parent);
                attributeName = metadata.GetString(typeReference.Name);
            }
            else if (memberReference.Parent.Kind == HandleKind.TypeDefinition)
            {
                var typeDefinition = metadata.GetTypeDefinition((TypeDefinitionHandle)memberReference.Parent);
                attributeName = metadata.GetString(typeDefinition.Name);
            }
            else
            {
                throw new NotImplementedException("Encountered unexpected attribute constructor parent handle: " + memberReference.Parent.Kind);
            }
        }
        else if (attribute.Constructor.Kind == HandleKind.MethodDefinition)
        {
            var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor);
            string methodName = metadata.GetString(methodDefinition.Name);
            var typeDefinitionHandle = methodDefinition.GetDeclaringType();
            var typeDefinition = metadata.GetTypeDefinition(typeDefinitionHandle);
            attributeName = metadata.GetString(typeDefinition.Name);
            if (methodName != ".ctor")
            {
                throw new NotImplementedException("Encountered unexpected method name: " + methodName);
            }
        }
        else
        {
            throw new NotImplementedException("Encountered unexpected attribute handle: " + attribute.Constructor.Kind);
        }
        
        Console.Write($"Reading attribute '{attributeName}'...");

        BlobReader blobReader = metadata.GetBlobReader(attribute.Value);
        
        var attributeValueLength = blobReader.Length;

        CustomAttributeValue<object> value;
        var decoder = new TypelessDecoder();
        try
        {
            value = attribute.DecodeValue(decoder);
            Console.WriteLine(" done!");
        }
        catch (BadImageFormatException)
        {
            Console.WriteLine(" found bad image format!");
        }
        catch (OutOfMemoryException) when (decoder.ArrayCount > 0) 
        {
            Console.WriteLine(" found OOM!");
        }
        
        var allocated = GC.GetTotalAllocatedBytes();
        Console.WriteLine($"Memory is at {allocated / (1024.0 * 1024)} MB");
        if (allocated > 1024 * 1024 * 1024)
        {
            Console.WriteLine("BIG MEMORY!");
            return;
        }
    }
}

class TypelessDecoder : ICustomAttributeTypeProvider<object>
{
    private int _arrayCount;
    public int ArrayCount => _arrayCount;

    public object GetPrimitiveType(PrimitiveTypeCode typeCode) => null;
    public object GetSystemType() => null;
    public object GetSZArrayType(object elementType)
    {
        Interlocked.Increment(ref _arrayCount);
        return null;
    }
    public object GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => null;
    public object GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => null;
    public object GetTypeFromSerializedName(string name) => null;
    public PrimitiveTypeCode GetUnderlyingEnumType(object type) => PrimitiveTypeCode.Int32;
    public bool IsSystemType(object type) => false;
}
stdout
Reading C:\Users\jver.REDMOND\Downloads\kentico.xperience.aspnet.mvc5.libraries.13.0.18\lib\NET48\Kentico.Content.Web.Mvc.dll...
Reading attribute 'ExtensionAttribute'... done!
Memory is at 0.10811614990234375 MB
Reading attribute 'CompilationRelaxationsAttribute'... done!
Memory is at 0.12369537353515625 MB
Reading attribute 'RuntimeCompatibilityAttribute'... done!
Memory is at 0.12369537353515625 MB
Reading attribute 'DebuggableAttribute'... done!
Memory is at 0.12369537353515625 MB
Reading attribute 'RegisterImplementationAttribute'... found bad image format!
Memory is at 0.6602554321289062 MB
Reading attribute 'RegisterImplementationAttribute'... found bad image format!
Memory is at 1.17730712890625 MB
Reading attribute 'RegisterImplementationAttribute'... found bad image format!
Memory is at 1.6943588256835938 MB
Reading attribute 'RegisterPageBuilderLocalizationResourceAttribute'... found bad image format!
Memory is at 28517.114097595215 MB
BIG MEMORY!

@ghost ghost added needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Jul 14, 2022
@joelverhagen
Copy link
Member Author

@steveharter - I did a ninja edit of my repro and output. I realized it wasn't clearly showing the problematic attribute that causes the memory spike.

@steveharter
Copy link
Member

@joelverhagen the implementation of ICustomAttributeTypeProvider needs an implementation of GetUnderlyingEnumType() that correctly returns the appropriate type so that the metadata reader can read the proper amount of bytes. I suspect that the reader is reading attributes with enums that have an underlying type that is not Int32 so in effect the underlying position is becoming corrupt.

@steveharter
Copy link
Member

Closing; please re-open if not accurate.

@steveharter steveharter removed the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Jul 18, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

No branches or pull requests

4 participants