Browse Source

properly handle char[] access and bool ref/out access

pull/728/head
Siegfried Pammer 9 years ago
parent
commit
0969abd8c9
  1. 19
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 4
      ICSharpCode.Decompiler/IL/NRTypeExtensions.cs
  3. 5
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystemUtils.cs

19
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -663,13 +663,16 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj(LdObj inst) protected internal override TranslatedExpression VisitLdObj(LdObj inst)
{ {
var target = Translate(inst.Target); var target = Translate(inst.Target);
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: false)) { if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can dereference the managed reference by stripping away the 'ref' // we can dereference the managed reference by stripping away the 'ref'
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
// we don't convert result to inst.Type, because the LdObj type // we don't convert result to inst.Type, because the LdObj type
// might be inaccurate (it's often System.Object for all reference types), // might be inaccurate (it's often System.Object for all reference types),
// and our parent node should already insert casts where necessary // and our parent node should already insert casts where necessary
result.Expression.AddAnnotation(inst); // add LdObj in addition to the existing ILInstruction annotation result.Expression.AddAnnotation(inst); // add LdObj in addition to the existing ILInstruction annotation
if (target.Type.IsSmallIntegerType() && inst.Type.IsSmallIntegerType() && target.Type.GetSign() != inst.Type.GetSign())
return result.ConvertTo(inst.Type, this);
return result; return result;
} else { } else {
// Cast pointer type if necessary: // Cast pointer type if necessary:
@ -685,7 +688,7 @@ namespace ICSharpCode.Decompiler.CSharp
var target = Translate(inst.Target); var target = Translate(inst.Target);
var value = Translate(inst.Value); var value = Translate(inst.Value);
TranslatedExpression result; TranslatedExpression result;
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: true)) { if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref' // we can deference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
} else { } else {
@ -702,7 +705,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// Gets whether reading/writing an element of accessType from the pointer /// Gets whether reading/writing an element of accessType from the pointer
/// is equivalent to reading/writing an element of the pointer's element type. /// is equivalent to reading/writing an element of the pointer's element type.
/// </summary> /// </summary>
bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType, bool isWrite) bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType)
{ {
IType memoryType; IType memoryType;
if (pointerType is PointerType) if (pointerType is PointerType)
@ -732,19 +735,23 @@ namespace ICSharpCode.Decompiler.CSharp
case KnownTypeCode.SByte: case KnownTypeCode.SByte:
// Reading small integers of different signs is not equivalent due to sign extension, // Reading small integers of different signs is not equivalent due to sign extension,
// but writes are equivalent (truncation works the same for signed and unsigned) // but writes are equivalent (truncation works the same for signed and unsigned)
return isWrite && (accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte)); return accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte);
case KnownTypeCode.Int16: case KnownTypeCode.Int16:
case KnownTypeCode.UInt16: case KnownTypeCode.UInt16:
return isWrite && (accessType.IsKnownType(KnownTypeCode.Int16) || accessType.IsKnownType(KnownTypeCode.UInt16)); return accessType.IsKnownType(KnownTypeCode.Int16) || accessType.IsKnownType(KnownTypeCode.UInt16);
case KnownTypeCode.Int32: case KnownTypeCode.Int32:
case KnownTypeCode.UInt32: case KnownTypeCode.UInt32:
return isWrite && (accessType.IsKnownType(KnownTypeCode.Int32) || accessType.IsKnownType(KnownTypeCode.UInt32)); return accessType.IsKnownType(KnownTypeCode.Int32) || accessType.IsKnownType(KnownTypeCode.UInt32);
case KnownTypeCode.IntPtr: case KnownTypeCode.IntPtr:
case KnownTypeCode.UIntPtr: case KnownTypeCode.UIntPtr:
return accessType.IsKnownType(KnownTypeCode.IntPtr) || accessType.IsKnownType(KnownTypeCode.UIntPtr); return accessType.IsKnownType(KnownTypeCode.IntPtr) || accessType.IsKnownType(KnownTypeCode.UIntPtr);
case KnownTypeCode.Int64: case KnownTypeCode.Int64:
case KnownTypeCode.UInt64: case KnownTypeCode.UInt64:
return accessType.IsKnownType(KnownTypeCode.Int64) || accessType.IsKnownType(KnownTypeCode.UInt64); return accessType.IsKnownType(KnownTypeCode.Int64) || accessType.IsKnownType(KnownTypeCode.UInt64);
case KnownTypeCode.Char:
return accessType.IsKnownType(KnownTypeCode.Char) || accessType.IsKnownType(KnownTypeCode.UInt16) || accessType.IsKnownType(KnownTypeCode.Int16);
case KnownTypeCode.Boolean:
return accessType.IsKnownType(KnownTypeCode.Boolean) || accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte);
} }
} }
return false; return false;

4
ICSharpCode.Decompiler/IL/NRTypeExtensions.cs

@ -70,7 +70,8 @@ namespace ICSharpCode.Decompiler.IL
public static Sign GetSign(this IType type) public static Sign GetSign(this IType type)
{ {
var typeDef = type.GetDefinition(); var typeForConstant = (type.Kind == TypeKind.Enum) ? type.GetDefinition().EnumUnderlyingType : type;
var typeDef = typeForConstant.GetDefinition();
if (typeDef == null) if (typeDef == null)
return Sign.None; return Sign.None;
switch (typeDef.KnownTypeCode) { switch (typeDef.KnownTypeCode) {
@ -85,6 +86,7 @@ namespace ICSharpCode.Decompiler.IL
return Sign.Signed; return Sign.Signed;
case KnownTypeCode.UIntPtr: case KnownTypeCode.UIntPtr:
case KnownTypeCode.Char: case KnownTypeCode.Char:
case KnownTypeCode.Boolean:
case KnownTypeCode.Byte: case KnownTypeCode.Byte:
case KnownTypeCode.UInt16: case KnownTypeCode.UInt16:
case KnownTypeCode.UInt32: case KnownTypeCode.UInt32:

5
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystemUtils.cs

@ -60,5 +60,10 @@ namespace ICSharpCode.Decompiler
{ {
return GetNativeSize(type1) >= GetNativeSize(type2) ? type1 : type2; return GetNativeSize(type1) >= GetNativeSize(type2) ? type1 : type2;
} }
public static bool IsSmallIntegerType(this IType type)
{
return GetNativeSize(type) < 4;
}
} }
} }

Loading…
Cancel
Save