Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
<Compile Include="TestCases\ILPretty\MonoFixed.cs" />
<Compile Include="TestCases\Pretty\Comparisons.cs" />
<Compile Include="TestCases\Pretty\Issue3406.cs" />
<Compile Include="TestCases\Pretty\PointerArithmetic.cs" />
<Compile Include="TestCases\Pretty\Issue3439.cs" />
<Compile Include="TestCases\Pretty\Issue3442.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,12 @@ public async Task MetadataAttributes([ValueSource(nameof(defaultOptions))] Compi
await RunForLibrary(cscOptions: cscOptions);
}

[Test]
public async Task PointerArithmetic([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}

async Task RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, Action<DecompilerSettings> configureDecompiler = null)
{
await Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, configureDecompiler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public unsafe void ProblemFunction(Guid[] A_0, int A_1)
fixed (Guid* ptr = A_0)
{
void* ptr2 = ptr;
UIntPtr* ptr3 = (UIntPtr*)((byte*)ptr2 - sizeof(UIntPtr));
UIntPtr* ptr3 = (UIntPtr*)ptr2 - 1;
UIntPtr uIntPtr = *ptr3;
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,16 @@ public unsafe string NegativeOffsets(int a, int b, int c)
#if OPT
byte* num = stackalloc byte[12];
*(int*)num = 1;
*(int*)(num - 4) = 2;
*(int*)(num - 8) = 3;
*((int*)num - 1) = 2;
*((int*)num - 2) = 3;
int* ptr = (int*)num;
Console.WriteLine(*ptr);
return UsePointer((byte*)ptr);
#else
byte* ptr = stackalloc byte[12];
*(int*)ptr = 1;
*(int*)(ptr - 4) = 2;
*(int*)(ptr - 8) = 3;
*((int*)ptr - 1) = 2;
*((int*)ptr - 2) = 3;
int* ptr2 = (int*)ptr;
Console.WriteLine(*ptr2);
return UsePointer((byte*)ptr2);
Expand Down
127 changes: 127 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/Pretty/PointerArithmetic.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;

namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class PointerArithmetic
{
public unsafe static void AssignmentVoidPointerToIntPointer(void* ptr)
{
((int*)ptr)[2] = 1;
}

public unsafe static int AccessVoidPointerToIntPointer(void* ptr)
{
return ((int*)ptr)[2];
}

public unsafe static void AssignmentLongPointerToIntPointer_2(long* ptr)
{
((int*)ptr)[2] = 1;
}

public unsafe static int AccessLongPointerToIntPointer_2(long* ptr)
{
return ((int*)ptr)[2];
}

public unsafe static void AssignmentLongPointerToIntPointer_3(long* ptr)
{
((int*)ptr)[3] = 1;
}

public unsafe static int AccessLongPointerToIntPointer_3(long* ptr)
{
return ((int*)ptr)[3];
}

public unsafe static void AssignmentGuidPointerToIntPointer(Guid* ptr)
{
((int*)ptr)[2] = 1;
}

public unsafe static int AccessGuidPointerToIntPointer(Guid* ptr)
{
return ((int*)ptr)[2];
}

public unsafe static uint AccessGuidPointerToUIntPointer(Guid* ptr)
{
return ((uint*)ptr)[2];
}

public unsafe static void AssignmentGuidPointerToDateTimePointer(Guid* ptr)
{
((DateTime*)ptr)[2] = DateTime.Now;
}

public unsafe static void AssignmentGuidPointerToDateTimePointerDefault(Guid* ptr)
{
((DateTime*)ptr)[2] = default(DateTime);
}

public unsafe static void AssignmentGuidPointerToDateTimePointer_2(Guid* ptr)
{
*(DateTime*)(ptr + 2) = DateTime.Now;
}

public unsafe static void AssignmentGuidPointerToDateTimePointerDefault_2(Guid* ptr)
{
*(DateTime*)(ptr + 2) = default(DateTime);
}

public unsafe static DateTime AccessGuidPointerToDateTimePointer(Guid* ptr)
{
return ((DateTime*)ptr)[2];
}

public unsafe static DateTime AccessGuidPointerToDateTimePointer_2(Guid* ptr)
{
return *(DateTime*)(ptr + 2);
}

public unsafe static void AssignmentIntPointer(int* ptr)
{
ptr[2] = 1;
}

public unsafe static int AccessIntPointer(int* ptr)
{
return ptr[2];
}

public unsafe static void AssignmentGuidPointer(Guid* ptr)
{
ptr[2] = Guid.NewGuid();
}

public unsafe static Guid AccessGuidPointer(Guid* ptr)
{
return ptr[2];
}

public unsafe static void AssignmentVoidPointerToGuidPointer(void* ptr)
{
((Guid*)ptr)[2] = Guid.NewGuid();
}

public unsafe static Guid AccessVoidPointerToGuidPointer(void* ptr)
{
return ((Guid*)ptr)[2];
}

public unsafe static void AssignmentIntPointerToGuidPointer(int* ptr)
{
((Guid*)ptr)[2] = Guid.NewGuid();
}

public unsafe static void AssignmentIntPointerToGuidPointer_2(int* ptr)
{
*(Guid*)(ptr + 2) = Guid.NewGuid();
}

public unsafe static Guid AccessIntPointerToGuidPointer(int* ptr)
{
return ((Guid*)ptr)[2];
}
}
}
3 changes: 2 additions & 1 deletion ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ public unsafe int PointerCasts()
{
int result = 0;
*(float*)(&result) = 0.5f;
((byte*)(&result))[3] = 3;
((sbyte*)(&result))[3] = 3;
((sbyte*)(&result))[3] = -1;
return result;
}

Expand Down
26 changes: 23 additions & 3 deletions ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ protected internal override TranslatedExpression VisitBinaryNumericInstruction(B
/// Returns null if 'inst' is not performing pointer arithmetic.
/// 'ptr - ptr' is not handled here, but in HandlePointerSubtraction()!
/// </summary>
TranslatedExpression? HandlePointerArithmetic(BinaryNumericInstruction inst, TranslatedExpression left, TranslatedExpression right)
TranslatedExpression? HandlePointerArithmetic(BinaryNumericInstruction inst, TranslatedExpression left, TranslatedExpression right, TranslationContext context)
{
if (!(inst.Operator == BinaryNumericOperator.Add || inst.Operator == BinaryNumericOperator.Sub))
return null;
Expand Down Expand Up @@ -1249,7 +1249,27 @@ protected internal override TranslatedExpression VisitBinaryNumericInstruction(B
{
return null;
}
TranslatedExpression offsetExpr = GetPointerArithmeticOffset(byteOffsetInst, byteOffsetExpr, pointerType.ElementType, inst.CheckForOverflow)
TranslatedExpression? offsetExpressionFromTypeHint = null;
if (context.TypeHint.Kind == TypeKind.Pointer)
{
// We use the type hint if one of the following is true:
// * The current element type is a non-primitive struct.
// * The current element type has a different size than the type hint element type.
// This prevents the type hint from overriding in undesirable situations (eg changing char* to short*).

var typeHint = (PointerType)context.TypeHint;
int elementTypeSize = pointerType.ElementType.GetSize();
if (elementTypeSize == 0 || typeHint.ElementType.GetSize() != elementTypeSize)
{
offsetExpressionFromTypeHint = GetPointerArithmeticOffset(byteOffsetInst, byteOffsetExpr, typeHint.ElementType, inst.CheckForOverflow);
if (offsetExpressionFromTypeHint != null)
{
pointerType = typeHint;
}
}
}
TranslatedExpression offsetExpr = offsetExpressionFromTypeHint
?? GetPointerArithmeticOffset(byteOffsetInst, byteOffsetExpr, pointerType.ElementType, inst.CheckForOverflow)
?? FallBackToBytePointer();

if (left.Type.Kind == TypeKind.Pointer)
Expand Down Expand Up @@ -1534,7 +1554,7 @@ TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOp
}
if (left.Type.Kind == TypeKind.Pointer || right.Type.Kind == TypeKind.Pointer)
{
var ptrResult = HandlePointerArithmetic(inst, left, right);
var ptrResult = HandlePointerArithmetic(inst, left, right, context);
if (ptrResult != null)
return ptrResult.Value;
}
Expand Down
Loading