Browse Source

Fix #2397: Introduced calls to Unsafe.Read or Unsafe.Write when we would otherwise cause "Cannot declare a pointer to a managed type T" errors.

pull/3058/head
Daniel Grunwald 2 years ago
parent
commit
03bceed0c1
  1. 8
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs
  2. 45
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

8
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs

@ -150,7 +150,7 @@ namespace System.Runtime.CompilerServices @@ -150,7 +150,7 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static T Read<T>(void* source)
{
return *(T*)source;
return Unsafe.Read<T>(source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -168,7 +168,7 @@ namespace System.Runtime.CompilerServices @@ -168,7 +168,7 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Write<T>(void* destination, T value)
{
*(T*)destination = value;
Unsafe.Write(destination, value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -186,13 +186,13 @@ namespace System.Runtime.CompilerServices @@ -186,13 +186,13 @@ namespace System.Runtime.CompilerServices
[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)]

45
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2797,6 +2797,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2797,6 +2797,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
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);
@ -2815,9 +2826,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2815,9 +2826,9 @@ namespace ICSharpCode.Decompiler.CSharp
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);
@ -2892,14 +2903,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2892,14 +2903,16 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
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);
}
@ -2911,12 +2924,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2911,12 +2924,24 @@ namespace ICSharpCode.Decompiler.CSharp
{
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)

Loading…
Cancel
Save