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.

release/8.1
Daniel Grunwald 2 years ago committed by Siegfried Pammer
parent
commit
7ce6ded97b
  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
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static T Read<T>(void* source) public unsafe static T Read<T>(void* source)
{ {
return *(T*)source; return Unsafe.Read<T>(source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -168,7 +168,7 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Write<T>(void* destination, T value) public unsafe static void Write<T>(void* destination, T value)
{ {
*(T*)destination = value; Unsafe.Write(destination, value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -186,13 +186,13 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Copy<T>(void* destination, ref T source) public unsafe static void Copy<T>(void* destination, ref T source)
{ {
*(T*)destination = source; Unsafe.Write(destination, source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void Copy<T>(ref T destination, void* source) public unsafe static void Copy<T>(ref T destination, void* source)
{ {
destination = *(T*)source; destination = Unsafe.Read<T>(source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

45
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2797,6 +2797,17 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
target = target.ConvertTo(new ByReferenceType(loadType), this); 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 else
{ {
target = target.ConvertTo(new PointerType(loadType), this); target = target.ConvertTo(new PointerType(loadType), this);
@ -2815,9 +2826,9 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStObj(StObj inst, TranslationContext context) 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); IType pointerTypeHint = inst.Target.ResultType == StackType.Ref ? new ByReferenceType(inst.Type) : (IType)new PointerType(inst.Type);
@ -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 // "unaligned.1; stobj" -> decompile to a call of
// Unsafe.WriteUnaligned<T>(void*, T) // Unsafe.WriteUnaligned<T>(void*, T)
// or Unsafe.WriteUnaligned<T>(ref byte, 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 pointer = Translate(inst.Target);
var value = Translate(inst.Value, typeHint: inst.Type); 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); pointer = pointer.ConvertTo(new ByReferenceType(compilation.FindType(KnownTypeCode.Byte)), this);
} }
@ -2911,12 +2924,24 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
value = value.ConvertTo(inst.Type, this); value = value.ConvertTo(inst.Type, this);
} }
return CallUnsafeIntrinsic( if (inst.UnalignedPrefix != 0)
name: "WriteUnaligned", {
arguments: new Expression[] { pointer, value }, return CallUnsafeIntrinsic(
returnType: compilation.FindType(KnownTypeCode.Void), name: "WriteUnaligned",
inst: inst 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) protected internal override TranslatedExpression VisitLdLen(LdLen inst, TranslationContext context)

Loading…
Cancel
Save