#4121·ILSpy

StateMachineHoistedLocalScopes rows are not aligned with the hoisted slots

Author: siegfriedpammerCreated Sep 8, 2026Updated Sep 8, 2026
LabelsBugPDBGen

Summary

StateMachineHoistedLocalScopes is indexed by slot number: a debugger parses N out of a state machine field name (<name>5__N, <>8__N) and reads row N-1 of the blob. PortablePdbWriter.BuildStateMachineHoistedLocalScopes (line 330) instead emits one row per surviving ILVariable that has a StateMachineField, ordered by field token, and gives every row the extent (0, CodeSize). That sequence has no relation to the slot numbering, so rows are misaligned, and where it is shorter than the highest slot the hoisted locals above the row count are dropped by the expression evaluator.

Reproduction

csharp
public static async Task<int> MixedAsync(IEnumerable<int> source)
{
	List<int> chunks = new List<int>();
	foreach (int value in source)
		chunks.Add(value);
	await Task.Yield();
	int total = 0;
	try
	{
		foreach (int chunk in chunks)
		{
			total += chunk;
			await Task.Yield();
		}
	}
	catch (InvalidOperationException e)
	{
		Console.WriteLine(e.Message);
	}
	return total;
}

State machine fields of <MixedAsync>d__0 (slots 1-7):

<>1__state, <>t__builder, source, <chunks>5__1, <total>5__2, <>s__3,
<value>5__4, <>s__5, <chunk>5__6, <e>5__7, <>u__1

Blob rows for <MixedAsync>d__0.MoveNext, start+length:

compiler:  0+24e, 0+24e, 0+0, 3c+25, 0+0, 124+8c, 1e8+1f
ILSpy:     0+24e, 0+24e, 0+24e, 0+24e, 0+24e, 0+24e, 0+24e

The compiler emits exactly one row per slot, in slot order, with an empty 0+0 placeholder for the synthesized <>s__N slots and the real live range for each user local. ILSpy's rows happen to number seven here, but they enumerate a different set (the hoisted parameter source is included, the <>s__N slots are not), so row N-1 does not describe slot N.

The counts diverge on real code: checking the PDB ILSpy generates against the highest user-visible slot in the binary reports a shortfall in 227 state machines of Newtonsoft.Json 13.0.4 and 2 of Microsoft.Extensions.Http 10.0.11. A shortfall means the hoisted locals whose slot exceeds the row count disappear from the Locals window entirely.

Note

#1230 lists StateMachineHoistedLocalScopes as unimplemented. It is emitted (PortablePdbWriter.cs lines 186-192), just not in the shape a consumer reads.

Posted by an AI agent (Claude) on Siegfried's behalf.