I have a simple C# function
public bool Isinst_intSimple(object value)
{
return value is int;
}
As expected Isinst_intSimple(0)
returns true
After decompiling, the function looks like:
IL_0000: nop
IL_0001: ldarg.1 // 'value'
IL_0002: isinst [System.Runtime]System.Int32
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.0 // V_0
IL_000b: br.s IL_000d
// [196 9 - 196 10]
IL_000d: ldloc.0 // V_0
IL_000e: ret
What will the IL_0002 isinst [System.Runtime]System.Int32
instruction push on the evaluation stack after execution (the input will be 0(int32))?
According to the MS documentation, the Isinst
instruction should return an object reference - The result (either an object reference or a null reference) is pushed onto the stack.
But what is the reference to 0? and if. What should the instruction IL_0008: cgt.un
do?
In my interpretation of all the IL instruction - the function retrun 0
. And I can't find a way to return true
.
Below is my interpretation of the function execution:
IL_0000: nop
IL_0001: ldarg.1 // push 0 on evaluation stack – stack after {0}
IL_0002: isinst [System.Runtime]System.Int32 //pop and object reference is pushed onto the stack. - stack after { 0* or reference to 0 – boxing? }
IL_0007: ldnull //– stack after {null, 0*}
IL_0008: cgt.un //– 0* is not greater than null so its return 0 - stack after {0}
IL_000a: stloc.0 // V_0 – pop to V_0 – stack after {}
IL_000b: br.s IL_000d // – stack after {}
// [196 9 - 196 10]
IL_000d: ldloc.0 // V_0 //– push V_0 – stack after {0}
IL_000e: ret //return {0}
I think the problem is in IL_0002: isinst
or IL_0008: cgt.un
, but I can't find it.
I'm working on a Virtual Machine that emulates C# dll - instruction by instruction (executing C# in "virtual machine") but I have problem simulating a test function Isinst_intSimple(0)
. My version return 0
but it should return true
ECMA-335 specification, which defines IL bytecode, says the following:
I.12.1.6.2.6
castclass
andisinst
on value typesCasting to and from value type instances isn’t permitted (the equivalent operations arebox and unbox). When boxed, however, it is possible to use the
isinst
instruction to see whether a value of typeSystem.Object
is the boxed representation of a particular class.
III.4.6 -
isinst
Test if
obj
is an instance oftypeTok
, returningnull
or an instance of that class or interface.Stack Transition: ..., obj => ..., result
Description:
typeTok
is a metadata token (a typeref, typedef or typespec), indicating the desired class. IftypeTok
is a non-nullable value type or a generic parameter type it is interpreted as “boxed”typeTok
Verifiability: Verification tracks the type of
result
astypeTok
.
So the result of isinst
on a value-type (struct) is a boxed ObjectRef to the value.
II.1.5 Operand type table
cgt.un
is allowed and verifiable on ObjectRefs (O). This is commonly used when comparing an ObjectRef with null (there is no “compare-not-equal” instruction, which would otherwise be a more obvious solution)
So isinst
ldnull
cgt.un
will tell you if an object is of a particular type