ajeh
ajeh

Reputation: 2784

Is there any sacred knowledge that I am missing in c# decompiled with Telerik JustDecompile?

Someone provided me with the source code for their utility that I need to reverse-engineer and replace. There are lots of assignments in the code like this:

var a = checked(checked(checked((int)SomeArray.Length) - 1) + 1);

Is this some design pattern that I am not aware of, or just the way it decompiles

var a = SomeArray.Length;

Upvotes: 0

Views: 111

Answers (3)

TsviatkoYov
TsviatkoYov

Reputation: 357

I won't be surprised if JustDecompile has the bug described by Kyle. I can't really remember getting any support requests involving checked so that part of the code hasn't really had a good sound reality check.

The chances are though that if the original code was checked(SomeArray.Length + 1 - 1) the compiler would cancel out the 1-1 part so it will never reach the decompiler.

Why don't you ask for the IL of that statement and post it here? Whoever decompiled it should be able to get the IL, too.

Upvotes: 0

Kyle
Kyle

Reputation: 6684

I've never known a C# compiler to emit extra arithmetic instructions when generating code for Array.Length. In IL, Array.Length looks something like this:

ldloc.1 // Assuming an array was stored in local slot 1
ldlen

Even in a checked context, that's what it looks like. Now, in IL there is no such thing as a checked context like there is in C#. IL just has different arithmetic instructions that are checked (e.g. add.ovf instead of add).

If someone wrote code like this:

int length = checked( array.Length - 1 + 1 );

The IL code that gets emitted looks something like this:

ldloc.1
ldlen
conv.i4
ldc.i4.1
sub.ovf
ldc.i4.1
add.ovf
stloc.2

It wouldn't surprise me if the decompiler treats each of those *.ovf instructions and the conv.i4 instruction as having its own checked context. Reading through the instructions and gradually building up a C# expression would get something like the following:

ldloc.1    // array
ldlen      // array.Length
conv.i4    // checked( (int) array.Length )
ldc.i4.1   
sub.ovf    // checked( checked( (int) array.Length ) - 1 )
ldc.i4.1
add.ovf    // checked( checked( checked( (int) array.Length ) - 1 ) + 1 )
stloc.2

Upvotes: 1

Steve Cooper
Steve Cooper

Reputation: 21480

Here's what I think is going on.

It's because the C# compiler is 'lossy,' in that the C# compiler figures out things like data type conversions, and then outputs those conversions directly into the DLL it's writing. All DLLs are written in CIL, which isn't as rich as C#, so complex checks and constructs are translated to more, but simpler, instructions.

For example, C# has the idea of lambda functions, but CIL doesn't, so the C# compiler will generate a class with a method on it, then call that method. E.g;

str => str.Length

becomes something like

class DisplayClass234
{
    public int Execute(string str) 
    {
         return str.Length;
    }
}

So then, if you try to decompile, Telerik sees the class "DisplayClass234" rather than the original lambda.

Upvotes: 0

Related Questions