Hmm, you fixed the dup but the generated code is still not correct. In fact it behaves identically to the old code. It occurred to me now that the problem is more complicated than the buggy dup.
The IL execution stack contains values. When you do a ldarg (or any other ld) the value stored in the variable is loaded on the stack. After a ld you can modify the variable in any way you like, the stack will still contain the original value of the variable.
Your compiler treats the stack differently, it seems to store references to variables instead of values. This means that whenever you use a stack location that "references" a variable, you get the current value of the variable, not the original one that existed at the time ld was executed.
Let's see this in the code:
dupValue0 = pStr; pStr = (Char*)(((Int32)dupValue0 + (Int32)2)); local0 = ((((UInt16)*(UInt16*)pStr) == 0) == 0);
Despite it being different, its behavior is exactly the same. The last statement still uses the modified value of pStr instead of using the original one. The correct code should look like this:
oldpStr = pStr; pStr = (Char*)(((Int32)pStr + (Int32)2)); local0 = ((((UInt16)*(UInt16*)oldpStr) == 0) == 0);
PS: editor problems: don't paste from VS, it seems that it generates html that confuses the post editor. Paste the code to notepad and then copy paste from notepad. This ensures that you paste plain text and not some weird html.