Problem with .maxstack in IL-roundtripping tools

At the IL level, the CLR needs to know the maximum stack depth of each method. This can be specified in ILasm via the “.maxstack” directive.In that post I wrongfully said that if you leave off the “.maxstack” directive from an IL body that ILasm will recompute the stack depth. My inline IL tool relied on that because it would intentionally strip the existing .maxstack directive, inject new IL into the method, and then expect ILasm to recompute a new value for the combined IL body.

It turns out that ILasm will actually just default to a value of 8 and not recompute the maximum stack depth. (Kudos to Mike Goatly for stumbling on this bug). Thus the inline IL tool is flawed. This limitation also makes tools based off round-tripping IL significantly less viable. I’ll update that original post with these new findings.

You can verify this. Say you have a trivial C# program (called t.cs), like the following:

class Foo { static void Main() { System.Console.WriteLine(“Hi!”); }}

1) Compile it: Csc t.cs

2) Then use ildasm to produce a file containing the IL (t.il). Ildasm t.exe /out=t.il

6) Inspect the resulting t.exe in ilasm and notice that the .maxstack directive is back and defaults to 8.

Just for kicks, edit t.il and change the .maxstack directive to something other than 8, like “.maxstack 19”. Repeat step 5 and 6 and you’ll see that the value 19 was preserved in the roundtripping.

I asked Serge Lidin (ILAsm guru in the CLR) about this. Defaulting to some arbitrary value seems very fragile. I specifically wondered why ILAsm wouldn’t just compute the maxstack if the the “.maxstack” directive was missing. Or at least flag a compile time error. Once you’ve parsed the IL, computing max-stack is very easy. In contrast, tools blindly manipulating IL snippets would take a high activation cost to figure out the maxstack. He agreed that would be good to recompute but explained that nobody had requested that feature. Maybe in V3 CLR.

FWIW, I think the default stack value of 8 comes from the CLI specification and not necessarily from ILAsm. In Partition II, "24.4.2 Tiny Format", it states when a tiny header is used as the method header type "The operand stack need be no bigger than 8 entries." But I agree that it would be cool to have ILAsm compute the .maxstack for you.