Exetools

Exetools (https://forum.exetools.com/index.php)
-   General Discussion (https://forum.exetools.com/forumdisplay.php?f=2)
-   -   Reflector gets wrong decompiling result? (https://forum.exetools.com/showthread.php?t=19134)

WhoCares 02-26-2019 13:05

Reflector gets wrong decompiling result?
 
same dll and same function body, different decompiling results for Reflector, dotPeek, dnSpy(all are latest versions).

Reflector
Code:

    private uint e(byte[] a, ref int b)
    {
        b += 4;
        return BitConverter.ToUInt32(a, b);
    }

dotPeek, dnSpy
Code:

  private uint e(byte[] a, ref int b)
  {
    int uint32 = (int) BitConverter.ToUInt32(a, b);
    b += 4;
    return (uint) uint32;
  }

IL of function body
Code:

  .method private hidebysig instance unsigned int32
    e(
      unsigned int8[] a,
      int32& b
    ) cil managed
  {
    .maxstack 8

    IL_0000: ldarg.1      // a
    IL_0001: ldarg.2      // b
    IL_0002: ldind.i4
    IL_0003: call        unsigned int32 [mscorlib]System.BitConverter::ToUInt32(unsigned int8[], int32)
    IL_0008: ldarg.2      // b
    IL_0009: ldarg.2      // b
    IL_000a: ldind.i4
    IL_000b: ldc.i4.4
    IL_000c: add
    IL_000d: stind.i4
    IL_000e: ret

  } // end of method e


chants 02-26-2019 13:16

Reflector has bad dataflow optimization semantics now apparently in ref arg cases

deepzero 02-26-2019 16:32

Nah, Reflector is the one who got it right.
Seems the others got thoroughly confused there ... int uint32 = ..

chants 02-27-2019 00:02

Yup I meant other way around, Reflector right

WhoCares 02-27-2019 10:40

"b +=4;", should appear first or last?

deepzero 02-27-2019 16:09

First.

Code:

    IL_0000: ldarg.1      // load a
    IL_0001: ldarg.2      // load b (which is a reference)
    IL_0002: ldind.i4      //dereference b (bc it is is reference: int&)
    IL_0003: call        BitConverter::ToUInt() //call and put result on stack

then

Code:

    IL_0008: ldarg.2      // load b on stack for later use
    IL_0009: ldarg.2      // load b
    IL_000a: ldind.i4      //dereference it
    IL_000b: ldc.i4.4      //load interger-constant "4" to stack
    IL_000c: add          //add the values of b and "4" and put the result on the stack

SO now the stack looks like this:


Code:

<value: result of b+4>
<reference: b> (was loaded at IL_0008)
<value: return value of the BitConverter call>


Then the last piece of the puzzle:

Code:

    IL_000d: stind.i4  //store the result of  "b+4" in b
There now is just one entry on the stack:

Code:

<value: return value of the BitConverter call>
and finally return that last entry:

Code:

    IL_000e: ret


So in conclusion the method does two things: 1) b += 4 and 2) return BitConverter(). So reflector is right and the others are wrong. You should file a bug report.


A more literal decompilation would be:


Code:

    private uint e(byte[] a, ref int b)
    {
        uint32 tmp = BitConverter.ToUInt32(a, b);
        b += 4;
        return tmp;
    }

But you can trivially optimize that by eliminating the tmp variable.

WhoCares 02-27-2019 21:32

ok, I understand those IL instructions now. thanks!

Besides ECMA specification, MS also documents the instructions:
https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldind_i4?view=netframework-4.7.2

chants 02-28-2019 04:51

However, if the referenced value (b) is unused, in all caller contexts which invoke this function, then theoretically
Quote:

b += 4
can be optimized out. Of course with reflection or exporting that would be somewhat impossible to deduce but these sorts of assumptions are more complicated issues even the compiler has to make decisions about and usually documented vaguely somewhere as to what guarantees are provided.

WhoCares 02-28-2019 11:30

"b" is used as an incremental pointer/index to the buffer "a", so "b +=4;" can't be optimized out.

Later there are more parsing of the buffer data by calling the function e(a, b) many times.

chants 03-09-2019 02:27

I just meant in those cases where caller never uses 'b' after the call then the assignment is optimizable (not the addition as you mention its an index):
Quote:

private uint e(byte[] a, ref int b)
{
return BitConverter.ToUInt32(a, b + 4);
}
Anyway that's too advanced an optimization anyway. But the bug found in multiple tools is a good one which should be reported and fixed.


All times are GMT +8. The time now is 22:11.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX