Browse Source

Merge pull request #3413 from ds5678/use-type-hint-in-pointer-arithmetic

Use type hint in pointer arithmetic
pull/3456/head
Daniel Grunwald 4 months ago committed by GitHub
parent
commit
b50d68c0b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.cs
  4. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs
  5. 127
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PointerArithmetic.cs
  6. 3
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  7. 26
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -137,6 +137,7 @@
<Compile Include="TestCases\ILPretty\MonoFixed.cs" /> <Compile Include="TestCases\ILPretty\MonoFixed.cs" />
<Compile Include="TestCases\Pretty\Comparisons.cs" /> <Compile Include="TestCases\Pretty\Comparisons.cs" />
<Compile Include="TestCases\Pretty\Issue3406.cs" /> <Compile Include="TestCases\Pretty\Issue3406.cs" />
<Compile Include="TestCases\Pretty\PointerArithmetic.cs" />
<Compile Include="TestCases\Pretty\Issue3439.cs" /> <Compile Include="TestCases\Pretty\Issue3439.cs" />
<Compile Include="TestCases\Pretty\Issue3442.cs" /> <Compile Include="TestCases\Pretty\Issue3442.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" /> <None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -730,6 +730,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions); 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) 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); await Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, configureDecompiler);

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.cs

@ -11,7 +11,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
fixed (Guid* ptr = A_0) fixed (Guid* ptr = A_0)
{ {
void* ptr2 = ptr; void* ptr2 = ptr;
UIntPtr* ptr3 = (UIntPtr*)((byte*)ptr2 - sizeof(UIntPtr)); UIntPtr* ptr3 = (UIntPtr*)ptr2 - 1;
UIntPtr uIntPtr = *ptr3; UIntPtr uIntPtr = *ptr3;
try try
{ {

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs

@ -222,16 +222,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#if OPT #if OPT
byte* num = stackalloc byte[12]; byte* num = stackalloc byte[12];
*(int*)num = 1; *(int*)num = 1;
*(int*)(num - 4) = 2; *((int*)num - 1) = 2;
*(int*)(num - 8) = 3; *((int*)num - 2) = 3;
int* ptr = (int*)num; int* ptr = (int*)num;
Console.WriteLine(*ptr); Console.WriteLine(*ptr);
return UsePointer((byte*)ptr); return UsePointer((byte*)ptr);
#else #else
byte* ptr = stackalloc byte[12]; byte* ptr = stackalloc byte[12];
*(int*)ptr = 1; *(int*)ptr = 1;
*(int*)(ptr - 4) = 2; *((int*)ptr - 1) = 2;
*(int*)(ptr - 8) = 3; *((int*)ptr - 2) = 3;
int* ptr2 = (int*)ptr; int* ptr2 = (int*)ptr;
Console.WriteLine(*ptr2); Console.WriteLine(*ptr2);
return UsePointer((byte*)ptr2); return UsePointer((byte*)ptr2);

127
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PointerArithmetic.cs

@ -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
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -212,7 +212,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
int result = 0; int result = 0;
*(float*)(&result) = 0.5f; *(float*)(&result) = 0.5f;
((byte*)(&result))[3] = 3; ((sbyte*)(&result))[3] = 3;
((sbyte*)(&result))[3] = -1;
return result; return result;
} }

26
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1220,7 +1220,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// Returns null if 'inst' is not performing pointer arithmetic. /// Returns null if 'inst' is not performing pointer arithmetic.
/// 'ptr - ptr' is not handled here, but in HandlePointerSubtraction()! /// 'ptr - ptr' is not handled here, but in HandlePointerSubtraction()!
/// </summary> /// </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)) if (!(inst.Operator == BinaryNumericOperator.Add || inst.Operator == BinaryNumericOperator.Sub))
return null; return null;
@ -1249,7 +1249,27 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
return null; 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(); ?? FallBackToBytePointer();
if (left.Type.Kind == TypeKind.Pointer) if (left.Type.Kind == TypeKind.Pointer)
@ -1534,7 +1554,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
if (left.Type.Kind == TypeKind.Pointer || right.Type.Kind == TypeKind.Pointer) 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) if (ptrResult != null)
return ptrResult.Value; return ptrResult.Value;
} }

Loading…
Cancel
Save