Question

I've just decompiled some 3rd party source to debug an issue, using DotPeek. The output code contains some unusual operators, which AFAIK aren't valid C#, so I'm wondering what they mean...

The extract looks like (with Dotpeek comments included, as they are probably relevant);

protected internal void DoReceive(ref byte[] Buffer, int MaxSize, out int Written)
{
    Written = 0;
    .
    .
    .        
    // ISSUE: explicit reference operation
    // ISSUE: variable of a reference type
    int& local = @Written;
    int num = SomeMethod();
    .
    .
    .
    // ISSUE: explicit reference operation
    ^local = num;
}

So, 3 unusual operators in there... int& = @Written seems to be assigning a pointer to a variable that is named pointlessly with the @ character?

But what is ^local = num; ???

OK, here is the equivalent snippet from ILSpy, which makes more sense, I guess the decompile to C# didn't produce a valid equivalent?

'C#'

 int& local = @Written;
 byte[] numArray2 = this.FInSpool;
 int num = (int) __Global.Min(numArray2 == null ? 0L : (long) numArray2.Length, (long) MaxSize);
 ^local = num;

IL

 byte[] expr_22 = this.FInSpool;
 Written = (int)__Global.Min((long)((expr_22 == null) ? 0 : expr_22.Length), (long)MaxSize);

So, I guess the 'C#' isn't quite valid? That IL would be valid C#, not sure why DotPeek produced the output it did. Perhaps I'll stick to ILSpy for this one...?

Was it helpful?

Solution

If you look at the raw IL (from ildasm, not the C# equivalent via IL Spy), that may help you see what the decompiler is trying to say. 'Out' parameters are represented using a (managed) typed-reference, which isn't explicitly exposed as a type in C#. 'Instances' of this type can normally only be passed as parameters to methods accepting typed references ('ref' or 'out' parameters.) See OpCodes.Mkrefany for more information.

What dotPeek is complaining about is that this 'out' typed reference was stored from the argument into a local variable slot, then written to later via the local slot. The '@' and '^' are placeholders used to indicate this unexpected behavior detected by the decompiler (the one the ISSUE comments describe.)

It's possible the code was compiled from C++/CLI and thus the IL looks different from the typical C# compiler output. It's also possible this is some level of minor obfuscation to confuse decompilers (though I don't think so.) I don't think this is functionally any different from loading the reference from its argument onto the operation stack directly (avoiding the use of a local variable slot), but I could be wrong.

OTHER TIPS

Putting a @ before a name allows you to use a reserved name for a variable, For example if I wanted to have a variable called return I would need to do this.

public int Weird()
{
    int @return = 0;
    return @return;
}

See this SO question for more details.


Putting a ^ before the name ... umm, no clue. (will update as I research I could find any info on what ^ means when not being used as a XOR)

It's clearly a decompilation issue. Because of broad set of languages supported decompiler to any particular language may not always find exact match, but still tries to produce some output. Decompiler MAY try to produce somewhat equivalent output, like in this case could be:

protected internal void DoReceive(ref byte[] Buffer, int MaxSize, out int Written)
{
    Written = 0;
    .        
    int num = SomeMethod();
    .
    Written = num;
}

but SHOULD it really do this? in this case decompiler actually provided you with a hint, so you could decide if this is important for your particular case, as there MAY be some side effects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top