From 587c55ca05e34e0324c3d65ad76f70bf14b8aa84 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 6 Jul 2026 09:46:10 +0200 Subject: [PATCH] Drop the bool result of the localloc prefix handler A true result meant both 'consumed a prefix' and 'no prefix present', while false aborted the whole transform. The distinction is unnecessary: a malformed or absent prefix leaves pos unchanged, so the per-element stobj scan fails on the initblk/cpblk instruction and rejects the transform with the same out-state. Aborting on 'no prefix' had also broken plain constant-length stackalloc initializers (element stores without any prefix), caught by CS73_StackAllocInitializers. Assisted-by: Claude:claude-fable-5:Claude Code --- .../Transforms/TransformArrayInitializers.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs index b2d3d640b..53ad08a16 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs @@ -428,10 +428,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms BlobReader blob = default; - if (lengthInstruction.MatchLdcI(out long byteCount) - && !TryHandleLocAllocInitializerPrefix(block, ref pos, store, byteCount, ref blob, ref instructionsToRemove)) + if (lengthInstruction.MatchLdcI(out long byteCount)) { - return false; + // An initblk/cpblk that does not fit the expected shape is left in place; + // the per-element stobj scan below then fails to match it and rejects the + // transform on its own. + HandleLocAllocInitializerPrefix(block, ref pos, store, byteCount, ref blob, ref instructionsToRemove); } for (int i = pos; i < block.Instructions.Count; i++) @@ -499,34 +501,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms return elementCount <= values.Length; } - bool TryHandleLocAllocInitializerPrefix(Block block, ref int pos, ILVariable store, long byteCount, ref BlobReader blob, ref int instructionsToRemove) + void HandleLocAllocInitializerPrefix(Block block, ref int pos, ILVariable store, long byteCount, ref BlobReader blob, ref int instructionsToRemove) { // initblk(ldloc store, value, byteCount) if (block.Instructions[pos].MatchInitblk(out var dest, out _, out var size)) { if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount)) - return false; + return; instructionsToRemove++; pos++; - return true; + return; } // cpblk(ldloc store, ldsflda/call get_Item(CreateSpan(field)) data, byteCount) if (block.Instructions[pos].MatchCpblk(out dest, out var src, out size)) { if (!dest.MatchLdLoc(store) || !size.MatchLdcI(byteCount)) - return false; + return; if (!MatchGetStaticFieldAddress(src, out var field)) - return false; + return; var fd = context.PEFile.Metadata.GetFieldDefinition((FieldDefinitionHandle)field.MetadataToken); if (!fd.HasFlag(System.Reflection.FieldAttributes.HasFieldRVA)) - return false; + return; blob = fd.GetInitialValue(context.PEFile, context.TypeSystem); instructionsToRemove++; pos++; } - - return true; } static bool TryGetSequentialStoreOffset(ILInstruction target, ILVariable store, IType elementType, long minExpectedOffset, out long offset, out bool abortTransform)