Skip to content

Commit

Permalink
Added walk around to Mono bug
Browse files Browse the repository at this point in the history
The bug (mono/mono#12747) caused exception when copying MarshalAsAttribute data.
Now parameter attributes are working, though with limitations.
Removed arrays from generating hash codes (they return just pointers)
  • Loading branch information
mcpiroman committed Feb 9, 2019
1 parent d3bbbdd commit 5561c06
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 26 deletions.
16 changes: 8 additions & 8 deletions src/DllManipulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ private static Type CreateDelegateTypeForNativeFunctionSignature(NativeFunctionS
var paramBuilder = invokeBuilder.DefineParameter(i + 1, param.parameterAttributes, null);
foreach(var attr in param.customAttributes)
{
paramBuilder.SetCustomAttribute(GetAttributeBuilderFromAttributeInstance(attr)); //Throws exception. See https://github.com/mono/mono/issues/12747
paramBuilder.SetCustomAttribute(GetAttributeBuilderFromAttributeInstance(attr));
}
}

Expand All @@ -396,17 +396,17 @@ private static CustomAttributeBuilder GetAttributeBuilderFromAttributeInstance(A
{
var ctor = attrType.GetConstructor(MARSHAL_AS_ATTRIBUTE_CTOR_PARAMETERS);
object[] ctorArgs = { marshalAsAttribute.Value };
var fieldArguments = new List<FieldInfo>();
var fieldArgumentValues = new List<object>();
foreach (var field in attrType.GetFields(BindingFlags.Public | BindingFlags.Instance))
var fields = attrType.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => f.FieldType.IsValueType).ToArray(); //XXX: Used to bypass Mono bug, see https://github.com/mono/mono/issues/12747
var fieldArgumentValues = new object[fields.Length];
for(int i = 0; i < fields.Length; i++)
{
fieldArguments.Add(field);
fieldArgumentValues.Add(field.GetValue(attribute));
fieldArgumentValues[i] = fields[i].GetValue(attribute);
}

//MarshalAsAttribute has no properties other than Value, which is passed in constructor
//MarshalAsAttribute has no properties other than Value, which is passed in constructor, hence empty properties array
return new CustomAttributeBuilder(ctor, ctorArgs, Array.Empty<PropertyInfo>(), Array.Empty<object>(),
fieldArguments.ToArray(), fieldArgumentValues.ToArray());
fields, fieldArgumentValues);
}
case InAttribute _:
{
Expand Down
86 changes: 68 additions & 18 deletions src/NativeFunctionSignature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,54 @@ public NativeFunctionSignature(MethodInfo methodInfo, CallingConvention callingC

public override bool Equals(object obj)
{
return obj is NativeFunctionSignature other &&
returnParameter.Equals(other.returnParameter) &&
parameters.SequenceEqual(other.parameters) &&
callingConvention == other.callingConvention &&
bestFitMapping == other.bestFitMapping &&
charSet == other.charSet &&
setLastError == other.setLastError &&
throwOnUnmappableChar == other.throwOnUnmappableChar;
var other = obj as NativeFunctionSignature;
if (other == null)
{
return false;
}

if(!returnParameter.Equals(other.returnParameter))
{
return false;
}

if (!parameters.SequenceEqual(other.parameters))
{
return false;
}

if (callingConvention != other.callingConvention)
{
return false;
}

if (bestFitMapping != other.bestFitMapping)
{
return false;
}

if (charSet != other.charSet)
{
return false;
}

if (setLastError != other.setLastError)
{
return false;
}

if (throwOnUnmappableChar != other.throwOnUnmappableChar)
{
return false;
}

return true;
}

public override int GetHashCode()
{
var hashCode = -1225548256;
var hashCode = 316391695;
hashCode = hashCode * -1521134295 + returnParameter.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<NativeFunctionParameterSignature[]>.Default.GetHashCode(parameters);
hashCode = hashCode * -1521134295 + callingConvention.GetHashCode();
hashCode = hashCode * -1521134295 + bestFitMapping.GetHashCode();
hashCode = hashCode * -1521134295 + charSet.GetHashCode();
Expand All @@ -63,7 +96,8 @@ public NativeFunctionParameterSignature(ParameterInfo parameterInfo)
{
this.type = parameterInfo.ParameterType;
this.parameterAttributes = parameterInfo.Attributes;
this.customAttributes = parameterInfo.GetCustomAttributes()
var attrs = parameterInfo.GetCustomAttributes(false).OfType<Attribute>(); //XXX: This is required way of obtaining attributes, since both CustomAttributeExtensions.GetCustomAttributes() and Attribute.GetCustomAttributes() return at most 1 attribute (mono bug?)
this.customAttributes = attrs
.Where(a => DllManipulator.SUPPORTED_PARAMATER_ATTRIBUTES.Contains(a.GetType()))
.ToArray();
}
Expand All @@ -78,18 +112,34 @@ public NativeFunctionParameterSignature(Type type, ParameterAttributes parameter
public override bool Equals(object obj)
{
var other = obj as NativeFunctionParameterSignature;
return other != null &&
type == other.type &&
parameterAttributes == other.parameterAttributes &&
customAttributes.Except(other.customAttributes).Any(); //Check if arrays have the same elements
if(other == null)
{
return false;
}

if (type != other.type)
{
return false;
}

if (parameterAttributes != other.parameterAttributes)
{
return false;
}

if (customAttributes.Except(other.customAttributes).Any()) //Check if arrays have the same elements
{
return false;
}

return true;
}

public override int GetHashCode()
{
var hashCode = 1477582057;
var hashCode = 424392846;
hashCode = hashCode * -1521134295 + type.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<Attribute[]>.Default.GetHashCode(customAttributes);
hashCode = hashCode * -1521134295 + customAttributes.GetHashCode();
hashCode = hashCode * -1521134295 + parameterAttributes.GetHashCode();
return hashCode;
}
}
Expand Down

0 comments on commit 5561c06

Please sign in to comment.