From 30e34d5a4d0f717cabf0a1b8672b1de825ec34fe Mon Sep 17 00:00:00 2001 From: Michael Voorhees Date: Wed, 5 Oct 2022 10:21:55 -0400 Subject: [PATCH] Fix a StackOverflowException reading windows runtime assemblies. During `AssemblyReader.ReadCustomAttributes` there is a call to `WindowsRuntimeProjections.Project` ``` if (module.IsWindowsMetadata ()) foreach (var custom_attribute in custom_attributes) WindowsRuntimeProjections.Project (owner, custom_attributes, custom_attribute); ``` `WindowsRuntimeProjections.Project` would call `WindowsRuntimeProjections.HasAttribute`, which would then call `type.CustomAttributes`, which would end up back in `AssemblyReader.ReadCustomAttributes`. This would lead to a StackOverflowException. This wasn't an issue previously. My PR https://github.com/jbevain/cecil/pull/843 caused this sequence of calls to start resulting in a StackOverflowException. Prior to my PR, there was a call to `metadata.RemoveCustomAttributeRange (owner);` before the call to `WindowsRuntimeProjections.Project`. This meant that when `WindowsRuntimeProjections.HasAttribute` would call `type.CustomAttributes`, we'd still end up in `AssemblyReader.ReadCustomAttributes`, however, no attributes would be found because the following if would be true and lead to returning an empty collection. ``` if (!metadata.TryGetCustomAttributeRanges (owner, out ranges)) return new Collection (); ``` The old behavior was probably the wrong. Although I'm not certain what the tangible impact was. The fix was pretty easy. `AssemblyReader.ReadCustomAttributes` will now pass in the custom attributes to `WindowsRuntimeProjections.Project` avoiding the need to call `type.CustomAttributes` --- Mono.Cecil/AssemblyReader.cs | 2 +- Mono.Cecil/WindowsRuntimeProjections.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index 0756fa884..4564071e8 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -2508,7 +2508,7 @@ public Collection ReadCustomAttributes (ICustomAttributeProvide if (module.IsWindowsMetadata ()) foreach (var custom_attribute in custom_attributes) - WindowsRuntimeProjections.Project (owner, custom_attribute); + WindowsRuntimeProjections.Project (owner, custom_attributes, custom_attribute); return custom_attributes; } diff --git a/Mono.Cecil/WindowsRuntimeProjections.cs b/Mono.Cecil/WindowsRuntimeProjections.cs index 6e83ba66e..b96a891b2 100644 --- a/Mono.Cecil/WindowsRuntimeProjections.cs +++ b/Mono.Cecil/WindowsRuntimeProjections.cs @@ -241,7 +241,7 @@ public static void Project (TypeDefinition type) treatment = TypeDefinitionTreatment.PrefixWindowsRuntimeName; if (treatment == TypeDefinitionTreatment.PrefixWindowsRuntimeName || treatment == TypeDefinitionTreatment.NormalType) - if (!type.IsInterface && HasAttribute (type, "Windows.UI.Xaml", "TreatAsAbstractComposableClassAttribute")) + if (!type.IsInterface && HasAttribute (type.CustomAttributes, "Windows.UI.Xaml", "TreatAsAbstractComposableClassAttribute")) treatment |= TypeDefinitionTreatment.Abstract; } else if (metadata_kind == MetadataKind.ManagedWindowsMetadata && IsClrImplementationType (type)) @@ -860,7 +860,7 @@ AssemblyNameReference GetAssemblyReference (string name) throw new Exception (); } - public static void Project (ICustomAttributeProvider owner, CustomAttribute attribute) + public static void Project (ICustomAttributeProvider owner, Collection owner_attributes, CustomAttribute attribute) { if (!IsWindowsAttributeUsageAttribute (owner, attribute)) return; @@ -876,7 +876,7 @@ public static void Project (ICustomAttributeProvider owner, CustomAttribute attr } if (treatment == CustomAttributeValueTreatment.None) { - var multiple = HasAttribute (type, "Windows.Foundation.Metadata", "AllowMultipleAttribute"); + var multiple = HasAttribute (owner_attributes, "Windows.Foundation.Metadata", "AllowMultipleAttribute"); treatment = multiple ? CustomAttributeValueTreatment.AllowMultiple : CustomAttributeValueTreatment.AllowSingle; } @@ -905,9 +905,9 @@ static bool IsWindowsAttributeUsageAttribute (ICustomAttributeProvider owner, Cu return declaring_type.Name == "AttributeUsageAttribute" && declaring_type.Namespace == /*"Windows.Foundation.Metadata"*/"System"; } - static bool HasAttribute (TypeDefinition type, string @namespace, string name) + static bool HasAttribute (Collection attributes, string @namespace, string name) { - foreach (var attribute in type.CustomAttributes) { + foreach (var attribute in attributes) { var attribute_type = attribute.AttributeType; if (attribute_type.Name == name && attribute_type.Namespace == @namespace) return true;