From 51b3cf51c6b3fc8a01880335bb56b3918eefe47a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 19 Feb 2021 19:35:47 +0100 Subject: [PATCH] Fix #2305: Cast to integer type where necessary in managed pointer arithmetic. --- .../TestCases/Pretty/UnsafeCode.cs | 5 +++ .../CSharp/ExpressionBuilder.cs | 39 ++++++++++++++++--- .../TypeSystem/INamedElement.cs | 2 + 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs index 2690a0a7a..7e2dda59c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs @@ -537,6 +537,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } #endif + private unsafe static int Issue2305(StructWithFixedSizeMembers value, StringComparison s) + { + return value.Integers[(int)s]; + } + private unsafe static void* CastToVoidPtr(IntPtr intptr) { return (void*)intptr; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index a8c3443f9..fdc13ffda 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1297,16 +1297,20 @@ namespace ICSharpCode.Decompiler.CSharp fieldAccess.RemoveAnnotations(); var result = fieldAccess.WithRR(new MemberResolveResult(mrr.TargetResult, mrr.Member, new PointerType(elementType))) .WithILInstruction(inst); - TranslatedExpression expr = new IndexerExpression(result.Expression, Translate(offsetInst).Expression) + right = TranslateArrayIndex(offsetInst); + TranslatedExpression expr = new IndexerExpression(result.Expression, right.Expression) .WithILInstruction(inst) .WithRR(new ResolveResult(elementType)); return new DirectionExpression(FieldDirection.Ref, expr) .WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, ReferenceKind.Ref)); } - return CallUnsafeIntrinsic(name, new[] { left.Expression, Translate(offsetInst).Expression }, brt, inst); + right = Translate(offsetInst); + right = ConvertArrayIndex(right, inst.RightInputType, allowIntPtr: true); + return CallUnsafeIntrinsic(name, new[] { left.Expression, right.Expression }, brt, inst); } else { + right = ConvertArrayIndex(right, inst.RightInputType, allowIntPtr: true); return CallUnsafeIntrinsic(name + "ByteOffset", new[] { left.Expression, right.Expression }, brt, inst); } } @@ -1324,13 +1328,16 @@ namespace ICSharpCode.Decompiler.CSharp ILInstruction offsetInst = PointerArithmeticOffset.Detect(inst.Left, brt.ElementType, inst.CheckForOverflow); if (offsetInst != null) { + left = Translate(offsetInst); + left = ConvertArrayIndex(left, inst.LeftInputType, allowIntPtr: true); return CallUnsafeIntrinsic("Add", new[] { - new NamedArgumentExpression("elementOffset", Translate(offsetInst)), + new NamedArgumentExpression("elementOffset", left), new NamedArgumentExpression("source", right) }, brt, inst); } else { + left = ConvertArrayIndex(left, inst.LeftInputType, allowIntPtr: true); return CallUnsafeIntrinsic("AddByteOffset", new[] { new NamedArgumentExpression("byteOffset", left.Expression), new NamedArgumentExpression("source", right) @@ -2921,11 +2928,31 @@ namespace ICSharpCode.Decompiler.CSharp TranslatedExpression TranslateArrayIndex(ILInstruction i) { var input = Translate(i); - if (i.ResultType == StackType.I4 && input.Type.IsSmallIntegerType() && input.Type.Kind != TypeKind.Enum) + return ConvertArrayIndex(input, i.ResultType, allowIntPtr: false); + } + + TranslatedExpression ConvertArrayIndex(TranslatedExpression input, StackType stackType, bool allowIntPtr) + { + if (input.Type.GetSize() > stackType.GetSize()) + { + // truncate oversized result + return input.ConvertTo(FindType(stackType, input.Type.GetSign()), this); + } + if (input.Type.IsCSharpPrimitiveIntegerType() || input.Type.IsCSharpNativeIntegerType()) + { + // can be used as array index as-is + return input; + } + if (allowIntPtr && (input.Type.IsKnownType(KnownTypeCode.IntPtr) || input.Type.IsKnownType(KnownTypeCode.UIntPtr))) + { + return input; + } + if (stackType != StackType.I4 && input.Type.GetStackType() == StackType.I4) { - return input; // we don't need a cast, just let small integers be promoted to int + // prefer casting to int if that's big enough + stackType = StackType.I4; } - IType targetType = FindArithmeticType(i.ResultType, input.Type.GetSign()); + IType targetType = FindArithmeticType(stackType, input.Type.GetSign()); return input.ConvertTo(targetType, this); } diff --git a/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs b/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs index 80d4528ff..677f3c83d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs +++ b/ICSharpCode.Decompiler/TypeSystem/INamedElement.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +#nullable enable + namespace ICSharpCode.Decompiler.TypeSystem { public interface INamedElement