Skip to content

Commit

Permalink
Fix #2397: Introduced calls to Unsafe.Read or Unsafe.Write when we wo…
Browse files Browse the repository at this point in the history
…uld otherwise cause "Cannot declare a pointer to a managed type T" errors.
  • Loading branch information
dgrunwald authored and siegfriedpammer committed Sep 16, 2023
1 parent bd77617 commit 7ce6ded
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 14 deletions.
8 changes: 4 additions & 4 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public static class Unsafe
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static T Read<T>(void* source)
{
return *(T*)source;
return Unsafe.Read<T>(source);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -168,7 +168,7 @@ public static T ReadUnaligned<T>(ref byte source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Write<T>(void* destination, T value)
{
*(T*)destination = value;
Unsafe.Write(destination, value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -186,13 +186,13 @@ public static void WriteUnaligned<T>(ref byte destination, T value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Copy<T>(void* destination, ref T source)
{
*(T*)destination = source;
Unsafe.Write(destination, source);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Copy<T>(ref T destination, void* source)
{
destination = *(T*)source;
destination = Unsafe.Read<T>(source);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
45 changes: 35 additions & 10 deletions ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2797,6 +2797,17 @@ ExpressionWithResolveResult LdObj(ILInstruction address, IType loadType)
{
target = target.ConvertTo(new ByReferenceType(loadType), this);
}
else if (!loadType.IsUnmanagedType(settings.IntroduceUnmanagedConstraint))
{
// Use: Unsafe.Read<T>(void*)
target = target.ConvertTo(new PointerType(compilation.FindType(KnownTypeCode.Void)), this, allowImplicitConversion: true);
return CallUnsafeIntrinsic(
name: "Read",
arguments: new Expression[] { target },
returnType: loadType,
typeArguments: new IType[] { loadType }
);
}
else
{
target = target.ConvertTo(new PointerType(loadType), this);
Expand All @@ -2815,9 +2826,9 @@ ExpressionWithResolveResult LdObj(ILInstruction address, IType loadType)

protected internal override TranslatedExpression VisitStObj(StObj inst, TranslationContext context)
{
if (inst.UnalignedPrefix != 0)
if (inst.UnalignedPrefix != 0 || (inst.Target.ResultType != StackType.Ref && !inst.Type.IsUnmanagedType(settings.IntroduceUnmanagedConstraint)))
{
return UnalignedStObj(inst);
return StObjViaHelperCall(inst);
}

IType pointerTypeHint = inst.Target.ResultType == StackType.Ref ? new ByReferenceType(inst.Type) : (IType)new PointerType(inst.Type);
Expand Down Expand Up @@ -2892,14 +2903,16 @@ protected internal override TranslatedExpression VisitStObj(StObj inst, Translat
}
}

private TranslatedExpression UnalignedStObj(StObj inst)
private TranslatedExpression StObjViaHelperCall(StObj inst)
{
// "unaligned.1; stobj" -> decompile to a call of
// Unsafe.WriteUnaligned<T>(void*, T)
// or Unsafe.WriteUnaligned<T>(ref byte, T)
// "stobj ManagedType" -> decompile to a call of
// Unsafe.Write<T>(void*, T)
var pointer = Translate(inst.Target);
var value = Translate(inst.Value, typeHint: inst.Type);
if (pointer.Expression is DirectionExpression)
if (pointer.Expression is DirectionExpression && inst.UnalignedPrefix != 0)
{
pointer = pointer.ConvertTo(new ByReferenceType(compilation.FindType(KnownTypeCode.Byte)), this);
}
Expand All @@ -2911,12 +2924,24 @@ private TranslatedExpression UnalignedStObj(StObj inst)
{
value = value.ConvertTo(inst.Type, this);
}
return CallUnsafeIntrinsic(
name: "WriteUnaligned",
arguments: new Expression[] { pointer, value },
returnType: compilation.FindType(KnownTypeCode.Void),
inst: inst
);
if (inst.UnalignedPrefix != 0)
{
return CallUnsafeIntrinsic(
name: "WriteUnaligned",
arguments: new Expression[] { pointer, value },
returnType: compilation.FindType(KnownTypeCode.Void),
inst: inst
);
}
else
{
return CallUnsafeIntrinsic(
name: "Write",
arguments: new Expression[] { pointer, value },
returnType: inst.Type,
inst: inst
);
}
}

protected internal override TranslatedExpression VisitLdLen(LdLen inst, TranslationContext context)
Expand Down

0 comments on commit 7ce6ded

Please sign in to comment.