Browse Source

Merge pull request #587 from LordJZ/case/pointer-handling-squashed

Enhanced pointer arithmetic handling
pull/620/head
Daniel Grunwald 10 years ago
parent
commit
08fe5177ef
  1. 6
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
  2. 127
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 5
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  4. 27
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

6
ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs

@ -35,7 +35,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -35,7 +35,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
protected override bool VisitChildren(AstNode node, object data)
{
bool result = false;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
AstNode next;
for (AstNode child = node.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue
// if the visitor removes/replaces child.
next = child.NextSibling;
result |= child.AcceptVisitor(this, data);
}
if (result && node is EntityDeclaration && !(node is Accessor)) {

127
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -669,35 +669,89 @@ namespace ICSharpCode.Decompiler.ILAst @@ -669,35 +669,89 @@ namespace ICSharpCode.Decompiler.ILAst
});
}
static void HandlePointerArithmetic(ILNode method)
void HandlePointerArithmetic(ILNode method)
{
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
List<ILExpression> args = expr.Arguments;
switch (expr.Code) {
case ILCode.Localloc:
args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
{
PointerType type = expr.InferredType as PointerType;
if (type != null) {
ILExpression arg0 = args[0];
ILExpression expr2 = expr;
DivideOrMultiplyBySize(ref expr2, ref arg0, type.ElementType, true);
// expr shouldn't change
if (expr2 != expr)
throw new InvalidOperationException();
args[0] = arg0;
}
break;
}
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
{
ILExpression arg0 = args[0];
ILExpression arg1 = args[1];
if (expr.InferredType is PointerType) {
if (args[0].ExpectedType is PointerType)
args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
else if (args[1].ExpectedType is PointerType)
args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
if (arg0.ExpectedType is PointerType) {
DivideOrMultiplyBySize(ref arg0, ref arg1, ((PointerType)expr.InferredType).ElementType, true);
} else if (arg1.ExpectedType is PointerType)
DivideOrMultiplyBySize(ref arg1, ref arg0, ((PointerType)expr.InferredType).ElementType, true);
}
args[0] = arg0;
args[1] = arg1;
break;
}
case ILCode.Sub:
case ILCode.Sub_Ovf:
case ILCode.Sub_Ovf_Un:
{
ILExpression arg0 = args[0];
ILExpression arg1 = args[1];
if (expr.InferredType is PointerType) {
if (args[0].ExpectedType is PointerType)
args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
if (arg0.ExpectedType is PointerType && !(arg1.InferredType is PointerType))
DivideOrMultiplyBySize(ref arg0, ref arg1, ((PointerType)expr.InferredType).ElementType, true);
}
args[0] = arg0;
args[1] = arg1;
break;
}
case ILCode.Conv_I8:
{
ILExpression arg0 = args[0];
// conv.i8(div:intptr(p0 - p1))
if (arg0.Code == ILCode.Div && arg0.InferredType.FullName == "System.IntPtr")
{
ILExpression dividend = arg0.Arguments[0];
if (dividend.InferredType.FullName == "System.IntPtr" &&
(dividend.Code == ILCode.Sub || dividend.Code == ILCode.Sub_Ovf || dividend.Code == ILCode.Sub_Ovf_Un))
{
PointerType pointerType0 = dividend.Arguments[0].InferredType as PointerType;
PointerType pointerType1 = dividend.Arguments[1].InferredType as PointerType;
if (pointerType0 != null && pointerType1 != null) {
if (pointerType0.ElementType.FullName == "System.Void" ||
pointerType0.ElementType.FullName != pointerType1.ElementType.FullName) {
pointerType0 = pointerType1 = new PointerType(typeSystem.Byte);
dividend.Arguments[0] = Cast(dividend.Arguments[0], pointerType0);
dividend.Arguments[1] = Cast(dividend.Arguments[1], pointerType1);
}
DivideOrMultiplyBySize(ref dividend, ref arg0, pointerType0.ElementType, false);
// dividend shouldn't change
if (args[0].Arguments[0] != dividend)
throw new InvalidOperationException();
}
}
}
args[0] = arg0;
break;
}
}
}
}
static ILExpression UnwrapIntPtrCast(ILExpression expr)
{
@ -720,12 +774,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -720,12 +774,24 @@ namespace ICSharpCode.Decompiler.ILAst
return expr;
}
static ILExpression DivideBySize(ILExpression expr, TypeReference type)
static ILExpression Cast(ILExpression expr, TypeReference type)
{
return new ILExpression(ILCode.Castclass, type, expr)
{
InferredType = type,
ExpectedType = type
};
}
void DivideOrMultiplyBySize(ref ILExpression pointerExpr, ref ILExpression adjustmentExpr, TypeReference elementType, bool divide)
{
expr = UnwrapIntPtrCast(expr);
adjustmentExpr = UnwrapIntPtrCast(adjustmentExpr);
ILExpression sizeOfExpression;
switch (TypeAnalysis.GetInformationAmount(type)) {
switch (TypeAnalysis.GetInformationAmount(elementType)) {
case 0: // System.Void
pointerExpr = Cast(pointerExpr, new PointerType(typeSystem.Byte));
goto case 1;
case 1:
case 8:
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1);
@ -740,34 +806,41 @@ namespace ICSharpCode.Decompiler.ILAst @@ -740,34 +806,41 @@ namespace ICSharpCode.Decompiler.ILAst
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8);
break;
default:
sizeOfExpression = new ILExpression(ILCode.Sizeof, type);
sizeOfExpression = new ILExpression(ILCode.Sizeof, elementType);
break;
}
if (expr.Code == ILCode.Mul || expr.Code == ILCode.Mul_Ovf || expr.Code == ILCode.Mul_Ovf_Un) {
ILExpression mulArg = expr.Arguments[1];
if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand))
return UnwrapIntPtrCast(expr.Arguments[0]);
if (divide && (adjustmentExpr.Code == ILCode.Mul || adjustmentExpr.Code == ILCode.Mul_Ovf || adjustmentExpr.Code == ILCode.Mul_Ovf_Un) ||
!divide && (adjustmentExpr.Code == ILCode.Div || adjustmentExpr.Code == ILCode.Div_Un)) {
ILExpression mulArg = adjustmentExpr.Arguments[1];
if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand)) {
adjustmentExpr = UnwrapIntPtrCast(adjustmentExpr.Arguments[0]);
return;
}
}
if (expr.Code == sizeOfExpression.Code) {
if (sizeOfExpression.Operand.Equals(expr.Operand))
return new ILExpression(ILCode.Ldc_I4, 1);
if (adjustmentExpr.Code == sizeOfExpression.Code) {
if (sizeOfExpression.Operand.Equals(adjustmentExpr.Operand)) {
adjustmentExpr = new ILExpression(ILCode.Ldc_I4, 1);
return;
}
if (expr.Code == ILCode.Ldc_I4) {
int offsetInBytes = (int)expr.Operand;
if (adjustmentExpr.Code == ILCode.Ldc_I4) {
int offsetInBytes = (int)adjustmentExpr.Operand;
int elementSize = (int)sizeOfExpression.Operand;
int offsetInElements = offsetInBytes / elementSize;
// ensure integer division
if (offsetInElements * elementSize == offsetInBytes) {
expr.Operand = offsetInElements;
return expr;
if (offsetInBytes % elementSize != 0) {
pointerExpr = Cast(pointerExpr, new PointerType(typeSystem.Byte));
return;
}
adjustmentExpr.Operand = offsetInBytes / elementSize;
return;
}
}
return new ILExpression(ILCode.Div_Un, null, expr, sizeOfExpression);
if (!(sizeOfExpression.Code == ILCode.Ldc_I4 && (int)sizeOfExpression.Operand == 1))
adjustmentExpr = new ILExpression(divide ? ILCode.Div_Un : ILCode.Mul, null, adjustmentExpr, sizeOfExpression);
}
public static void ReplaceVariables(ILNode node, Func<ILVariable, ILVariable> variableMapping)

5
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -1044,7 +1044,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1044,7 +1044,10 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, null);
TypeReference rightPreferred = InferTypeForExpression(right, null);
// subtracting two pointers is not a pointer
if (rightPreferred is PointerType)
return typeSystem.IntPtr;
return leftPreferred;
}
if (IsEnum(leftPreferred)) {

27
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -130,7 +130,7 @@ public class UnsafeCode @@ -130,7 +130,7 @@ public class UnsafeCode
public unsafe byte* PointerArithmetic2(long* p, int y, int x)
{
return (byte*)p + (y * x);
return (byte*)((short*)p + (y * x));
}
public unsafe long* PointerArithmetic3(long* p)
@ -138,6 +138,31 @@ public class UnsafeCode @@ -138,6 +138,31 @@ public class UnsafeCode
return (long*)((byte*)p + 3);
}
public unsafe long* PointerArithmetic4(void* p)
{
return (long*)((byte*)p + 3);
}
public unsafe int PointerArithmetic5(void* p, byte* q, int i)
{
return (int)(q[i] + *(byte*)p);
}
public unsafe int PointerSubtraction(long* p, long* q)
{
return (int)((long)(p - q));
}
public unsafe int PointerSubtraction2(long* p, short* q)
{
return (int)((long)((byte*)p - (byte*)q));
}
public unsafe int PointerSubtraction3(void* p, void* q)
{
return (int)((long)((byte*)p - (byte*)q));
}
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);

Loading…
Cancel
Save