Skip to content

Commit

Permalink
Fix a StackOverflowException reading windows runtime assemblies.
Browse files Browse the repository at this point in the history
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 #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<CustomAttribute> ();
```

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`
  • Loading branch information
mrvoorhe committed Oct 5, 2022
1 parent e052ab5 commit 30e34d5
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Mono.Cecil/AssemblyReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2508,7 +2508,7 @@ public Collection<CustomAttribute> 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;
}
Expand Down
10 changes: 5 additions & 5 deletions Mono.Cecil/WindowsRuntimeProjections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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<CustomAttribute> owner_attributes, CustomAttribute attribute)
{
if (!IsWindowsAttributeUsageAttribute (owner, attribute))
return;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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<CustomAttribute> 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;
Expand Down

0 comments on commit 30e34d5

Please sign in to comment.