From aa914058ceefa36c3a2bfcb293128e5be6b155a7 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 21 Jul 2024 12:32:58 +0200 Subject: [PATCH] Fix #3237: Use `ref readonly` locals for `readonly.ldelema` --- ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs | 3 +++ .../Transforms/IntroduceRefReadOnlyModifierOnLocals.cs | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 49ff62cc2..7b38b2e90 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -537,6 +537,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } + /// + /// Gets whether the ILInstruction will turn into a C# expresion that is considered readonly by the C# compiler. + /// internal static bool IsReadonlyReference(ILInstruction addr) { switch (addr) diff --git a/ICSharpCode.Decompiler/IL/Transforms/IntroduceRefReadOnlyModifierOnLocals.cs b/ICSharpCode.Decompiler/IL/Transforms/IntroduceRefReadOnlyModifierOnLocals.cs index 946f15363..aba272b1f 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/IntroduceRefReadOnlyModifierOnLocals.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/IntroduceRefReadOnlyModifierOnLocals.cs @@ -52,8 +52,18 @@ namespace ICSharpCode.Decompiler.IL { foreach (var store in variable.StoreInstructions.OfType()) { + // Check if C# requires that the local is ref-readonly in order to allow the store: if (ILInlining.IsReadonlyReference(store.Value)) return true; + // Check whether the local needs to be ref-readonly to avoid changing the semantics of + // a readonly.ldelema: + ILInstruction val = store.Value; + while (val is LdFlda ldflda) + { + val = ldflda.Target; + } + if (val is LdElema { IsReadOnly: true }) + return true; } return false; }