Browse Source

#1195: Fix several issues decompiling SharpSvn.dll (C++/CLI)

pull/1243/head
Daniel Grunwald 7 years ago
parent
commit
ba0a3af3c4
  1. 42
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 8
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  3. 2
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 5
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  5. 1
      ICSharpCode.Decompiler/IL/ILVariable.cs
  6. 6
      ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
  7. 17
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  8. 4
      ICSharpCode.Decompiler/TypeSystem/NullableType.cs
  9. 16
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs
  10. 5
      ILSpy/TextView/DecompilerTextView.cs

42
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1448,9 +1448,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1448,9 +1448,11 @@ namespace ICSharpCode.Decompiler.CSharp
// We need to convert to inst.TargetType, or to an equivalent type.
IType targetType;
if (inst.TargetType == NullableType.GetUnderlyingType(context.TypeHint).ToPrimitiveType()
&& NullableType.IsNullable(context.TypeHint) == inst.IsLifted)
{
&& NullableType.IsNullable(context.TypeHint) == inst.IsLifted) {
targetType = context.TypeHint;
} else if (inst.TargetType == IL.PrimitiveType.Ref) {
// converting to unknown ref-type
targetType = new ByReferenceType(compilation.FindType(KnownTypeCode.Byte));
} else {
targetType = GetType(inst.TargetType.ToKnownTypeCode());
}
@ -1691,7 +1693,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1691,7 +1693,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj(LdObj inst, TranslationContext context)
{
var target = Translate(inst.Target);
if (TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
if (TypeUtils.IsCompatiblePointerTypeForMemoryAccess(target.Type, inst.Type)) {
TranslatedExpression result;
if (target.Expression is DirectionExpression dirExpr) {
// we can dereference the managed reference by stripping away the 'ref'
@ -1735,27 +1737,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1735,27 +1737,35 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStObj(StObj inst, TranslationContext context)
{
var target = Translate(inst.Target);
TranslatedExpression result;
if (target.Expression is DirectionExpression && TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
var pointer = Translate(inst.Target);
TranslatedExpression target;
TranslatedExpression value = default;
if (pointer.Expression is DirectionExpression && TypeUtils.IsCompatiblePointerTypeForMemoryAccess(pointer.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
target = pointer.UnwrapChild(((DirectionExpression)pointer.Expression).Expression);
} else {
// Cast pointer type if necessary:
if (!TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
target = target.ConvertTo(new PointerType(inst.Type), this);
if (!TypeUtils.IsCompatiblePointerTypeForMemoryAccess(pointer.Type, inst.Type)) {
value = Translate(inst.Value, typeHint: inst.Type);
if (TypeUtils.IsCompatibleTypeForMemoryAccess(value.Type, inst.Type)) {
pointer = pointer.ConvertTo(new PointerType(value.Type), this);
} else {
pointer = pointer.ConvertTo(new PointerType(inst.Type), this);
}
}
if (target.Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.AddressOf) {
if (pointer.Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.AddressOf) {
// *&ptr -> ptr
result = target.UnwrapChild(uoe.Expression);
target = pointer.UnwrapChild(uoe.Expression);
} else {
result = new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
target = new UnaryOperatorExpression(UnaryOperatorType.Dereference, pointer.Expression)
.WithoutILInstruction()
.WithRR(new ResolveResult(((TypeWithElementType)target.Type).ElementType));
.WithRR(new ResolveResult(((TypeWithElementType)pointer.Type).ElementType));
}
}
var value = Translate(inst.Value, typeHint: result.Type);
return Assignment(result, value).WithILInstruction(inst);
if (value.Expression == null) {
value = Translate(inst.Value, typeHint: target.Type);
}
return Assignment(target, value).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdLen(LdLen inst, TranslationContext context)
@ -1834,7 +1844,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1834,7 +1844,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
TranslatedExpression arrayExpr = Translate(inst.Array);
var arrayType = arrayExpr.Type as ArrayType;
if (arrayType == null || !TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(arrayType.ElementType), inst.Type)) {
if (arrayType == null || !TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, inst.Type)) {
arrayType = new ArrayType(compilation, inst.Type, inst.Indices.Count);
arrayExpr = arrayExpr.ConvertTo(arrayType, this);
}

8
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -300,7 +300,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -300,7 +300,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
for (int i = 0; i < instructionCount; i++) {
foreach (var branch in workItem.Instructions[i].Descendants.OfType<Branch>()) {
if (branch.TargetBlock.Parent == sourceContainer) {
Debug.Assert(branch.TargetBlock != block);
if (branch.TargetBlock == block) {
// pin instruction is within a loop, and can loop around without an unpin instruction
// This should never happen for C#-compiled code, but may happen with C++/CLI code.
return false;
}
if (reachedEdgesPerBlock[branch.TargetBlock.ChildIndex]++ == 0) {
// detected first edge to that block: add block as work item
workList.Enqueue(branch.TargetBlock);
@ -442,7 +446,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -442,7 +446,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if ((inst is LdLoc || inst is StLoc) && !IsSlotAcceptingBothManagedAndUnmanagedPointers(inst.SlotInfo) && oldVar.StackType != StackType.I) {
// wrap inst in Conv, so that the stack types match up
var children = inst.Parent.Children;
children[inst.ChildIndex] = new Conv(inst, PrimitiveType.I, false, Sign.None);
children[inst.ChildIndex] = new Conv(inst, oldVar.StackType.ToPrimitiveType(), false, Sign.None);
}
} else if (inst.MatchLdStr(out var val) && val == "Is this ILSpy?") {
inst.ReplaceWith(new LdStr("This is ILSpy!")); // easter egg ;)

2
ICSharpCode.Decompiler/IL/ILReader.cs

@ -202,7 +202,7 @@ namespace ICSharpCode.Decompiler.IL @@ -202,7 +202,7 @@ namespace ICSharpCode.Decompiler.IL
ILVariable CreateILVariable(int index, IType type)
{
VariableKind kind;
if (type is PinnedType pinned) {
if (type.SkipModifiers() is PinnedType pinned) {
kind = VariableKind.PinnedLocal;
type = pinned.ElementType;
} else {

5
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -160,9 +160,8 @@ namespace ICSharpCode.Decompiler.IL @@ -160,9 +160,8 @@ namespace ICSharpCode.Decompiler.IL
return new ByReferenceType(ldsflda.Field.Type);
case LdElema ldelema:
if (ldelema.Array.InferType() is ArrayType arrayType) {
var refType = new ByReferenceType(arrayType.ElementType);
if (TypeUtils.IsCompatibleTypeForMemoryAccess(refType, ldelema.Type)) {
return refType;
if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type)) {
return new ByReferenceType(arrayType.ElementType);
}
}
return new ByReferenceType(ldelema.Type);

1
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.IL @@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.IL
NamedArgument,
}
[DebuggerDisplay("{Name} : {Type}")]
public class ILVariable
{
VariableKind kind;

6
ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs

@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
{
if (inst.Target.MatchLdLoca(out ILVariable v)
&& TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type)
&& TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type)
&& inst.UnalignedPrefix == 0
&& !inst.IsVolatile)
{
@ -72,11 +72,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -72,11 +72,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal static bool LdObjToLdLoc(LdObj inst, ILTransformContext context)
{
if (inst.Target.MatchLdLoca(out ILVariable v)
&& TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type)
&& TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type)
&& inst.UnalignedPrefix == 0
&& !inst.IsVolatile)
{
context.Step($"ldobj(ldloca {v.Name}, ...) => ldloc {v.Name}(...)", inst);
context.Step($"ldobj(ldloca {v.Name}) => ldloc {v.Name}", inst);
inst.ReplaceWith(new LdLoc(v) { ILRange = inst.ILRange });
return true;
}

17
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -112,19 +112,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -112,19 +112,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!SemanticHelper.IsPure(stobj.Target.Flags) || inst.Variable.IsUsedWithin(stobj.Target))
return false;
var newType = stobj.Target.InferType();
if (newType is ByReferenceType byref)
newType = byref.ElementType;
else if (newType is PointerType pointer)
newType = pointer.ElementType;
else
newType = stobj.Type;
var pointerType = stobj.Target.InferType();
IType newType = stobj.Type;
if (TypeUtils.IsCompatiblePointerTypeForMemoryAccess(pointerType, stobj.Type)) {
if (pointerType is ByReferenceType byref)
newType = byref.ElementType;
else if (pointerType is PointerType pointer)
newType = pointer.ElementType;
}
if (IsImplicitTruncation(inst.Value, newType)) {
// 'stobj' is implicitly truncating the value
return false;
}
stobj.Type = newType;
context.Step("Inline assignment stobj", stobj);
stobj.Type = newType;
block.Instructions.Remove(localStore);
block.Instructions.Remove(stobj);
stobj.Value = inst.Value;

4
ICSharpCode.Decompiler/TypeSystem/NullableType.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (type == null)
throw new ArgumentNullException("type");
ParameterizedType pt = type as ParameterizedType;
ParameterizedType pt = type.SkipModifiers() as ParameterizedType;
return pt != null && pt.TypeParameterCount == 1 && pt.GenericType.IsKnownType(KnownTypeCode.NullableOfT);
}
@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (type == null)
throw new ArgumentNullException("type");
ParameterizedType pt = type as ParameterizedType;
ParameterizedType pt = type.SkipModifiers() as ParameterizedType;
if (pt != null && pt.TypeParameterCount == 1 && pt.GenericType.IsKnownType(KnownTypeCode.NullableOfT))
return pt.GetTypeArgument(0);
else

16
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -192,13 +192,26 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -192,13 +192,26 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// The access semantics may sligthly differ on read accesses of small integer types,
/// due to zero extension vs. sign extension when the signs differ.
/// </remarks>
public static bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType)
public static bool IsCompatiblePointerTypeForMemoryAccess(IType pointerType, IType accessType)
{
IType memoryType;
if (pointerType is PointerType || pointerType is ByReferenceType)
memoryType = ((TypeWithElementType)pointerType).ElementType;
else
return false;
return IsCompatibleTypeForMemoryAccess(memoryType, accessType);
}
/// <summary>
/// Gets whether reading/writing an element of accessType from the pointer
/// is equivalent to reading/writing an element of the memoryType.
/// </summary>
/// <remarks>
/// The access semantics may sligthly differ on read accesses of small integer types,
/// due to zero extension vs. sign extension when the signs differ.
/// </remarks>
public static bool IsCompatibleTypeForMemoryAccess(IType memoryType, IType accessType)
{
memoryType = memoryType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
accessType = accessType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
if (memoryType.Equals(accessType))
@ -363,6 +376,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -363,6 +376,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
type = type.SkipModifiers();
if (type.Kind == TypeKind.Unknown) return PrimitiveType.Unknown;
if (type.Kind == TypeKind.ByReference) return PrimitiveType.Ref;
var def = type.GetEnumUnderlyingType().GetDefinition();
return def != null ? def.KnownTypeCode.ToPrimitiveType() : PrimitiveType.None;
}

5
ILSpy/TextView/DecompilerTextView.cs

@ -730,13 +730,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -730,13 +730,8 @@ namespace ICSharpCode.ILSpy.TextView
tcs.SetResult(output);
} catch (OperationCanceledException) {
tcs.SetCanceled();
#if DEBUG
} catch (AggregateException ex) {
tcs.SetException(ex);
#else
} catch (Exception ex) {
tcs.SetException(ex);
#endif
}
}));
thread.Start();

Loading…
Cancel
Save