Using System.Reflection.Emit.ILGenerator to call Random in VB.Net? - cil

I'm generating output for a .Net executable from my own language... the opcode (called 'Random') that's being translated from my language is supposed to create a random number within a specific range.
The goal for my code is to produce the random number using System.Reflection.Emit.ILGenerator class... to understand how the CIL code looks I've created some vb.net code:
Sub Main()
Dim A As Random
A = New Random
Console.WriteLine(A.Next(100))
End Sub
Which ILDASM reports as:
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] class [mscorlib]System.Random A)
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Random::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 100
IL_000a: callvirt instance int32 [mscorlib]System.Random::Next(int32)
IL_000f: call void [mscorlib]System.Console::WriteLine(int32)
IL_0014: nop
IL_0015: nop
IL_0016: ret
} // end of method Main::Main
I can reproduce everything using the ILGenerator.Emit method; except the line IL_0001 ("newobj instance void [mscorlib]System.Random::.ctor()")...
Hopefully I haven't overwhelmed anyone with too much information. But I figure it's better to be verbose when describing a problem that seems complex to me.
Finally I have the code that I've produced so far:
Sub EmitRandom()
Dim NewRandom As New Random
Dim stringtype As Type = GetType(System.Random)
Dim paramtypes() As Type = {GetType(Integer)}, blankparams() As Type = {}
'Dim RandomMethod = stringtype.GetMethod("New", paramtypes)
m_ILGen.Emit(OpCodes.Newobj, New Random().GetType)
EmitStoreInLocal(tempVariableRnd)
EmitLoadLocal(tempVariableRnd)
m_ILGen.Emit(OpCodes.Callvirt, stringtype.GetMethod("Next", paramtypes))
End Sub
Which emits the following code:
.
.
.
IL_0073: newobj [mscorlib]System.Random
IL_0078: stloc.2
IL_0079: ldloc.2
IL_007a: callvirt instance int32 [mscorlib]System.Random::Next(int32)
.
.
.
Things that I've tried already:
Coming up with a way to point IL_Gen.Emit(OpCodes.NewObj, ... ctor())... can't figure out how.
Coming up with a way to point to New() - since that seems to be what .ctor() is... New can't be used as anything but an initializer.
Just disabling the Random function until I can come up with a better way of emitting.
The problem seems hard to me but I know there's someone out there who understands code generation and MSIL more easily than I do and who is willing to point out an answer.
Thanks for your time,
Dominick

You need to use the ConstructorInfo:
m_ILGen.Emit(OpCodes.Newobj, GetType(Random).GetConstructor(Type.EmptyTypes))
Also - the storing and loading from local are unnecessary. You really just want the equivalent of new Random().Next(100), right?...in which case storing and loading from a local never happens.

Related

How can i import this Dll

I have a "CLock.dll" have some functions
For example: This is document for a function
__int16 __stdcall dv_get_auth_code(unsigned char* auth);
Function
To gain authorization code of setup card.
Parameters
auth:[out] Return authorization code, 6 characters.
Return
Succeed then return 0.
I need to call this dll in my winform application. I try
[DllImport("CLock.dll",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int dv_get_auth_code([Out]StringBuilder auth);`
and in Main()
My code:
StringBuilder sb = new StringBuilder();
int result = dv_get_auth_code(sb);
But it's working. What should i do? Thank you and have a nice day !
There are two mistakes in the code as presented. The return type is wrong, and no buffer is allocated.
The return type is a 16 bit type, in C# that is short:
[DllImport("Clock.dll")]
public static extern short dv_get_auth_code(StringBuilder auth);
Then to call the function you need to allocate a buffer. I don't know how large that buffer should be, presumably you know that.
StringBuilder sb = new StringBuilder(bufferLengtg);
short result = dv_get_auth_code(sb);
It is always wise for such an API to pass the length of the buffer to the function. Then it can make sure it does not overrun the buffer.

Why does SonarQ say 'Using' block does not dispose?

Here is what Sonar is saying:
EnsureLocalDisposalRule Open Updated: 6 days Technical debt: 1 hours
Local 'da' of type 'SqlDataAdapter' is not guaranteed to be disposed of.
Here is the code:
conn1.Open()
Using da As New SqlDataAdapter(qry, conn1)
'fill data set 1 for combobox
da.Fill(ds1)
End Using
ds1.Dispose()
With CompanyCbx
'what the user sees
.DisplayMember = "CMPNY_NM"
'value behind each display member
.ValueMember = "CMPNY_SEQ_ID"
.DataSource = ds1.Tables(0)
.SelectedIndex = 0
End With
'close connection
conn1.Close()
'Dispose connection
conn1.Dispose()
The documentation regarding the Using block states that it disposes of whatever it is 'using,' so I don't understand the error.
Here is Sonar's documentation:
EnsureLocalDisposalRule
This rule checks that disposable locals are always disposed of before the method returns. Use a 'using' statement (or a try/finally block) to guarantee local disposal even in the event an unhandled exception occurs.
Link to the official Mono Gendarme documentation
I would guess that this is just a bug in Sonar's analysis. C# and VB.Net generate slightly different IL for logically the same using code and this difference often throws off decompilers. Generally they are tuned for C# code and miss the subtle difference in VB.Net and hence believe it to be a manual try / finally instead of using
The key difference is that the VB.Net null check in the finally is more complex than the C# one.
C#
IL_000b: ldloc.0
IL_000c: ldnull
IL_000d: ceq
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: brtrue.s IL_001a
VB.Net
IL_000c: ldloc.0
IL_000d: ldnull
IL_000e: ceq
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: stloc.1
IL_0014: ldloc.1
IL_0015: brfalse.s IL_001e
C# essentially takes the result of ceq and branches on that while VB.Net takes the result, inverts it and then branches on false. Functionally it does the same but the subtle difference often throws off code analysis

Trouble using PInvoke against ssdeep's fuzzy.dll (unbalanced stack)

I'm attempting to call a method on the ssdeep fuzzy.dll
The .h file is here and a friendly reference is here
Specifically, I'm trying to call this method....
int fuzzy_hash_filename (
const char * filename,
char * result
)
I've got the following...
<DllImport("C:\SSDeep\Fuzzy.dll", EntryPoint:="fuzzy_hash_filename")>
Private Shared Function fuzzy_hash_filename(
<InAttribute(),
MarshalAsAttribute(UnmanagedType.LPStr)>
ByVal Filename As String, ByVal Result As StringBuilder) As Integer
End Function
Public Shared Function FuzzyHash(Filename As String) As String
Dim Ret As New StringBuilder
Ret.Capacity = NativeConstants.FUZZY_MAX_RESULT
Dim Success = fuzzy_hash_filename(Filename, Ret)
If Success <> 0 Then
Throw New Exception("SSDeep fuzzy hashing failed")
End If
Return Ret.ToString
End Function
If I run this code, VS gives me a modal dialogue
A call to PInvoke function '(Blah)::fuzzy_hash_filename' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
(FWIW The call seems to succeed if I ignore the warning so I must be close)
What change do I need to make to my definition to get this going?
I found someone that had the same issue on MSDN forums:
Concerning the PInvokeStackImbalance.
1.1 This is usually due to mismatch of the calling convention used by the API and that declared for the API in the C# code.
1.2 By default, if the CallingConvention argument for the DllImportAttribute is not set, then StdCall is used by default.
1.3 If the DoSomething() API is to use __cdecl (as is the default in C++ projects), then you should use the following declaration for
DoSomething() in the C# code : [DllImport(#"dll.dll",
CallingConvention=CallingConvention.Cdecl)]
1.4 Also, I suggest that you declare the API as extern "C" otherwise it will be subject to name mangling by the C++ compiler.
The accepted answer appears to have solved the original asker's problem, but the equivalent code in c# did not work for me. After trying increasingly complex annotations, going back to basics eventually did work. For everyone's reference, I include the declaration for three of the interface functions and working code (built against ssdeep version 2.9).
//Note: StringBuilder here is the standard way to do it, but is a perf hit because unicode stringbuilder can't be pinned when martialling char*.
//See http://msdn.microsoft.com/en-us/magazine/cc164193.aspx#S4
//int fuzzy_hash_buf(const unsigned char *buf, uint32_t buf_len, char *result)
[DllImport("fuzzy.dll")]
public static extern int fuzzy_hash_buf(StringBuilder buf, int buf_len, StringBuilder result);
//int fuzzy_hash_filename(const char* filename, char* result)
[DllImport("fuzzy.dll")]
static extern int fuzzy_hash_filename(string filename, StringBuilder result);
//int fuzzy_compare (const char *sig1, const char *sig2)
[DllImport("fuzzy.dll")]
static extern int fuzzy_compare(string sig1, string sig2);
static void Main(string[] args)
{
StringBuilder buf = new StringBuilder("test");
StringBuilder result0 = new StringBuilder(150);
fuzzy_hash_buf(buf, 4, result0);
Console.WriteLine(result0);
string filename = "test.txt";
StringBuilder result1 = new StringBuilder(150);
fuzzy_hash_filename(filename, result1);
Console.WriteLine(result1);
int matchScore = fuzzy_compare(result0.ToString(), result1.ToString());
Console.WriteLine("MatchScore: " + matchScore);
}
Output:
ssdeeptest.exe
3:Hn:Hn
24:gRnIM7stweRp+fEWU1XRk+/M98D6Dv3JrEeEnD/MGQbnEWqv3JW:gRIMwtrMU1Bk2I3Jrg53JW
MatchScore: 0

CIL and Array Bound Checking

Let us assume the following CIL program:
.assembly extern mscorlib {}
.assembly Program {}
.method private static void Main() cil managed
{
.entrypoint
.maxstack 4
.locals init ( int32[] a,
uint32 t )
// Creates an array of int of size 10
ldc.i4 10
newarr int32
stloc.0
// Writes 0xaabbccdd at the index 2 of the array
ldloc.0
ldc.i4.2
ldc.i4 0xaabbccdd
stelem.i4
// Loads
ldloc.0
ldc.i4 9 // <HERE>
ldelem.i1
stloc.1
ldstr "Value: 0x{0:x8}"
ldloc.1
box [mscorlib]System.UInt32
call void [mscorlib]System.Console::WriteLine(string, object)
ret
}
This program:
creates an array of int size 10
writes 0xaabbccdd at index 2 of the array
tries to read one byte in the array using ldelem.i1
prints the result
The trick is that I use "ldelem.i1" instead of the more standard "idelem.i4" for performance issues (I want to avoid doing masking) The idea is to access to the data of the array the way one does with pointers in C.
But things are not so nice because the program crashes (IndexOutOfRangeException) for indexes of more than 10 as argument for ldelem.i1.
This males the trick useless as I can't access data after the first half of the integer at the third index.
Ideally, I want to access bytes up to index 39, which corresponds to the last byte of the integer at index 9.
I would very much appreciate if somebody had some ideas on this point.
Interesting. The ECMA-335 states that it will throw an exception if the index is greater than or equal to the size of the array, which it definitely is. What surprises me about this isn't that the exception is thrown, but that the index is treated as a byte index into an int array in the first place - I can't see that that's specified anywhere.
I suspect you're into the realms of unspecified behaviour, quite possibly behaviour which isn't intended to be specified - I suspect you're just not meant to use ldelem.i1 on an int array.

Is it possible to indirectly load a value type on the stack

In Microsoft IL, to call a method on a value type you need an indirect reference. Lets say we have an ILGenerator named "il" and that currently we have a Nullable on top of the stack, if we want to check whether it has a value then we could emit the following:
var local = il.DeclareLocal(typeof(Nullable<int>));
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ldloca, local);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
However it would be nice to skip saving it as a local variable, and simply call the method on the address of the variable already on the stack, something like:
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
The ldind family of instructions looks promising (particularly ldind_ref) but I can't find sufficient documentation to know whether this would cause boxing of the value, which I suspect it might.
I've had a look at the C# compiler output, but it uses local variables to achieve this, which makes me believe the first way may be the only way. Anyone have any better ideas?
**** Edit: Additional Notes ****
Attempting to call the method directly, as in the following program with the lines commented out, doesn't work (the error will be "Operation could destabilise the runtime"). Uncomment the lines and you'll see that it does work as expected, returning "True".
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
//var local = il.DeclareLocal(typeof(Nullable<int>));
//il.Emit(OpCodes.Stloc, local);
//il.Emit(OpCodes.Ldloca, local);
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
So you can't simply call the method with the value on the stack because it's a value type (though you could if it was a reference type).
What I'd like to achieve (or to know whether it is possible) is to replace the three lines that are shown commented out, but keep the program working, without using a temporary local.
I figured it out! Luckily I was reading about the unbox opcode and noticed that it pushes the address of the value. unbox.any pushes the actual value. So, in order to call a method on a value type without having to store it in a local variable and then load its address, you can simply box followed by unbox. Using your last example:
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Box, typeof(Nullable<int>)); // box followed by unbox
il.Emit(OpCodes.Unbox, typeof(Nullable<int>));
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
The downside to this is that boxing causes memory allocation for the boxed object, so it is a bit slower than using local variables (which would already be allocated). But, it saves you from having to determine, declare, and reference all of the local variables you need.
If the variable is already on the stack, you can go ahead and just emit the method call.
It seems that the constructor doesn't push the variable on the stack in a typed form. After digging into the IL a bit, it appears there are two ways of using the variable after constructing it.
You can load the variable that will store the reference onto the evaluation stack before calling the constructor, and then load that variable again after calling the constructor like so:
DynamicMethod method = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
ILGenerator il = method.GetILGenerator();
Type nullable = typeof(Nullable<int>);
ConstructorInfo ctor = nullable.GetConstructor(new Type[] { typeof(int) });
MethodInfo getValue = nullable.GetProperty("HasValue").GetGetMethod();
LocalBuilder value = il.DeclareLocal(nullable);
// load the variable to assign the value from the ctor to
il.Emit(OpCodes.Ldloca_S, value);
// load constructor args
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Call, ctor);
il.Emit(OpCodes.Ldloca_S, value);
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(method.Invoke(null, null));
The other option is doing it the way you have shown. The only reason for this that I can see is that the ctor methods return void, so they don't put their value on the stack like other methods. It does seem strange that you can call Setloc if the new object isn't on the stack.
After looking at the options some more and further consideration, I think you're right in assuming it can't be done. If you examine the stack behaviour of MSIL instructions, you can see that no op leaves its operand(s) on the stack. Since this would be a requirement for a 'get address of stack entry' op, I'm fairly confident one doesn't exist.
That leaves you with either dup+box or stloc+ldloca. As you've pointed out, the latter is likely more efficient.
#greg: Many instructions leave their result on the stack, but no instructions leave any of their operands on the stack, which would be required for a 'get stack element address' instruction.
Just wrote a class that does what the OP is asking... here's the IL code that C# compiler produces:
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_000f: stfld valuetype [mscorlib]System.Nullable`1<int32> ConsoleApplication3.Temptress::_X
IL_0014: nop
IL_0015: ret