Skip to content

Commit 5561c06

Browse files
committed
Added walk around to Mono bug
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)
1 parent d3bbbdd commit 5561c06

2 files changed

Lines changed: 76 additions & 26 deletions

File tree

src/DllManipulator.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ private static Type CreateDelegateTypeForNativeFunctionSignature(NativeFunctionS
379379
var paramBuilder = invokeBuilder.DefineParameter(i + 1, param.parameterAttributes, null);
380380
foreach(var attr in param.customAttributes)
381381
{
382-
paramBuilder.SetCustomAttribute(GetAttributeBuilderFromAttributeInstance(attr)); //Throws exception. See https://github.com/mono/mono/issues/12747
382+
paramBuilder.SetCustomAttribute(GetAttributeBuilderFromAttributeInstance(attr));
383383
}
384384
}
385385

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

407-
//MarshalAsAttribute has no properties other than Value, which is passed in constructor
407+
//MarshalAsAttribute has no properties other than Value, which is passed in constructor, hence empty properties array
408408
return new CustomAttributeBuilder(ctor, ctorArgs, Array.Empty<PropertyInfo>(), Array.Empty<object>(),
409-
fieldArguments.ToArray(), fieldArgumentValues.ToArray());
409+
fields, fieldArgumentValues);
410410
}
411411
case InAttribute _:
412412
{

src/NativeFunctionSignature.cs

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,54 @@ public NativeFunctionSignature(MethodInfo methodInfo, CallingConvention callingC
2929

3030
public override bool Equals(object obj)
3131
{
32-
return obj is NativeFunctionSignature other &&
33-
returnParameter.Equals(other.returnParameter) &&
34-
parameters.SequenceEqual(other.parameters) &&
35-
callingConvention == other.callingConvention &&
36-
bestFitMapping == other.bestFitMapping &&
37-
charSet == other.charSet &&
38-
setLastError == other.setLastError &&
39-
throwOnUnmappableChar == other.throwOnUnmappableChar;
32+
var other = obj as NativeFunctionSignature;
33+
if (other == null)
34+
{
35+
return false;
36+
}
37+
38+
if(!returnParameter.Equals(other.returnParameter))
39+
{
40+
return false;
41+
}
42+
43+
if (!parameters.SequenceEqual(other.parameters))
44+
{
45+
return false;
46+
}
47+
48+
if (callingConvention != other.callingConvention)
49+
{
50+
return false;
51+
}
52+
53+
if (bestFitMapping != other.bestFitMapping)
54+
{
55+
return false;
56+
}
57+
58+
if (charSet != other.charSet)
59+
{
60+
return false;
61+
}
62+
63+
if (setLastError != other.setLastError)
64+
{
65+
return false;
66+
}
67+
68+
if (throwOnUnmappableChar != other.throwOnUnmappableChar)
69+
{
70+
return false;
71+
}
72+
73+
return true;
4074
}
4175

4276
public override int GetHashCode()
4377
{
44-
var hashCode = -1225548256;
78+
var hashCode = 316391695;
4579
hashCode = hashCode * -1521134295 + returnParameter.GetHashCode();
46-
hashCode = hashCode * -1521134295 + EqualityComparer<NativeFunctionParameterSignature[]>.Default.GetHashCode(parameters);
4780
hashCode = hashCode * -1521134295 + callingConvention.GetHashCode();
4881
hashCode = hashCode * -1521134295 + bestFitMapping.GetHashCode();
4982
hashCode = hashCode * -1521134295 + charSet.GetHashCode();
@@ -63,7 +96,8 @@ public NativeFunctionParameterSignature(ParameterInfo parameterInfo)
6396
{
6497
this.type = parameterInfo.ParameterType;
6598
this.parameterAttributes = parameterInfo.Attributes;
66-
this.customAttributes = parameterInfo.GetCustomAttributes()
99+
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?)
100+
this.customAttributes = attrs
67101
.Where(a => DllManipulator.SUPPORTED_PARAMATER_ATTRIBUTES.Contains(a.GetType()))
68102
.ToArray();
69103
}
@@ -78,18 +112,34 @@ public NativeFunctionParameterSignature(Type type, ParameterAttributes parameter
78112
public override bool Equals(object obj)
79113
{
80114
var other = obj as NativeFunctionParameterSignature;
81-
return other != null &&
82-
type == other.type &&
83-
parameterAttributes == other.parameterAttributes &&
84-
customAttributes.Except(other.customAttributes).Any(); //Check if arrays have the same elements
115+
if(other == null)
116+
{
117+
return false;
118+
}
119+
120+
if (type != other.type)
121+
{
122+
return false;
123+
}
124+
125+
if (parameterAttributes != other.parameterAttributes)
126+
{
127+
return false;
128+
}
129+
130+
if (customAttributes.Except(other.customAttributes).Any()) //Check if arrays have the same elements
131+
{
132+
return false;
133+
}
134+
135+
return true;
85136
}
86137

87138
public override int GetHashCode()
88139
{
89-
var hashCode = 1477582057;
140+
var hashCode = 424392846;
90141
hashCode = hashCode * -1521134295 + type.GetHashCode();
91-
hashCode = hashCode * -1521134295 + EqualityComparer<Attribute[]>.Default.GetHashCode(customAttributes);
92-
hashCode = hashCode * -1521134295 + customAttributes.GetHashCode();
142+
hashCode = hashCode * -1521134295 + parameterAttributes.GetHashCode();
93143
return hashCode;
94144
}
95145
}

0 commit comments

Comments
 (0)