I had a customer who was seeing several invalid handle exceptions in his application. These exceptions were thrown during finalization of SafeProcessHandle objects. In their code they had a big collection of SafeProcessHandle objects hence too many objects in Finalization queue as well which means too many Invalid Handle exceptions as well.
What’s an Invalid Handle exception?
Invalid handle exceptions basically means the handle being closed has gone bad or has already been closed. In this case the second reason looked more valid to me as the exceptions were happening during finalization. There was a good chance that these handles got closed pretty early.
What’s the reason for these Invalid Handle exceptions?
Lots of Invalid handle exceptions were happening in his code while disposing a SafeProcessHandle object. This was because he’s was not properly serializing the process handles or SafeProcessHandle’s across app domain calls. We enabled MDA – ReleaseHandleFailed. This setting is also reporting something similar.
ReleaseHandleFailed was detected:
Message: A SafeHandle or CriticalHandle of type SafeProcessHandle failed to properly release the handle with value 0x00000000000020F0. This usually indicates that the handle was released incorrectly via another means (such as extracting the handle using DangerousGetHandle and closing it directly or building another SafeHandle around it.)
How to fix these Invalid Handle exceptions?
The only way to fix this invalid handle issue is to manage serialization of SafeProcessHandle objects across app domains. As of now its just a bitwise copy which results in two SafeProcessHandle’s owning a non-ref counted process handle. When either of these SafeProcessHandle objects are destroyed the second instance of SafeProcessHandle is bound to fail as the handle has already been destroyed/closed by the first instance.
Handle’s are indexes into a process handle table which in turn points to the real Kernel Object. This basically means we’ll have to duplicate this handle via DuplicateHandle API and which tells Kernel this object is still alive and not to destroy this Kernel Object. The duplicate handle refers to the same object as the original handle. Therefore, any changes to the object are reflected through both handles. For example, if you duplicate a file handle, the current file position is always the same for both handles.
SafeSerializableProcessHandle to fix Invalid Handle exceptions
Hence SafeSerializableProcessHandle is born. I wrote a dedicated class to manage this serialization. Made this class serializable as well. This class will automatically create a duplicate handle when serialized. For duplicating process handles we’re using the Windows API DuplicateHandle. Here’s how the code looks like…
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Diagnostics;
namespace NativeHandleWrappers
{
[System.Security.SecurityCritical]
[Serializable()]
public class SafeSerializableProcessHandle : SafeHandleZeroOrMinusOneIsInvalid, ISerializable
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, EntryPoint = "CloseHandle", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandleImport(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, EntryPoint = "DuplicateHandle", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DuplicateHandleImport(IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
out SafeSerializableProcessHandle lpTargetHandle,
uint dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
uint dwOptions);
[Flags]
public enum DuplicateOptions : uint
{
DUPLICATE_CLOSE_SOURCE = (0x00000001),// Closes the source handle. This occurs regardless of any error status returned.
DUPLICATE_SAME_ACCESS = (0x00000002), //Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.
}
// Constructors //
private SafeSerializableProcessHandle()
: base(true)
{
handle = IntPtr.Zero;
}
// Constructor that is called automatically during deserialization.
// Reconstructs the object from the information in SerializationInfo info
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
private SafeSerializableProcessHandle(SerializationInfo Info, StreamingContext Context)
: base(true)
{
handle = ((IntPtr)Info.GetInt64("handle"));
}
public SafeSerializableProcessHandle(IntPtr handle)
: base(true)
{
SetHandle(handle);
}
// End constructors //
// 0 is an Invalid Handle
internal static SafeSerializableProcessHandle InvalidHandle
{
get { return new SafeSerializableProcessHandle(IntPtr.Zero); }
}
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
override protected bool ReleaseHandle()
{
bool Status = true;
if (!SuppressRelease)
{
Status = CloseHandleImport(handle);
if (!Status)
{
DebugOutLastError();
}
}
return Status;
}
void DebugOutLastError()
{
System.ComponentModel.Win32Exception we = new System.ComponentModel.Win32Exception();
Debug.WriteLine("\n------------------------------------------\nLast error: " + we.Message + "\n------------------------------------------\n");
}
private bool _suppressRelease = false;
protected bool SuppressRelease
{
get
{
return _suppressRelease;
}
set
{
_suppressRelease = value;
}
}
// Serializes the object.
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
SafeSerializableProcessHandle hDupHandle = DuplicateHandlePrivate(handle);
info.AddValue("handle", hDupHandle.handle.ToInt64());
// Suppress close handle as the handle will be closed by the instance that's deserializing
hDupHandle.SuppressRelease = true;
hDupHandle.Close();
}
private SafeSerializableProcessHandle DuplicateHandlePrivate(IntPtr Handle)
{
SafeSerializableProcessHandle hDupHandle;
bool Status = DuplicateHandleImport(Process.GetCurrentProcess().Handle,
Handle,
Process.GetCurrentProcess().Handle,
out hDupHandle,
0,
true,
(uint)DuplicateOptions.DUPLICATE_SAME_ACCESS);
if (hDupHandle == null || !Status)
{
Debug.Assert(false);
DebugOutLastError();
}
return hDupHandle;
}
}
}
//Function to test SafeSerializableProcessHandle class. This function also demonstrates usage of SafeSerializableProcessHandle
void Serialize()
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Create|FileMode.CreateNew);
try
{
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
// Serialize
Process [] Proc = Process.GetProcessesByName("Explorer");
SafeSerializableProcessHandle ssph = OpenProcess(ProcessAccessFlags.DupHandle | ProcessAccessFlags.Terminate, true, Proc[0].Id);
formatter.Serialize(fs, ssph);
//Deserialize.
fs.Position = 0;
SafeSerializableProcessHandle newssph = (SafeSerializableProcessHandle)formatter.Deserialize(fs);
// Close both, this should work
ssph.Close();
newssph.Close();
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
Usage of SafeSerializableProcessHandle
Replace instances of SafeProcessHandle, which will be cross domained or serialized, with SafeSerializableProcessHandle. No other change will be needed. The effect is magical, no invalid handle exceptions any more. 🙂
Caveats/Disclaimer
Please note this class is not extensively tested. I did some basic tests and so far looks like this is working for our customer as well. So I guess this is pretty solid. If you run into issues you can let me know via a comment to this post but this post is given as is without any sort of support. You’re going to use this at your own risk.
Being a .net developer you might have wondered if at all there is a way to tell .net assembly binding and loading mechanism (fusion) to look for your assemblies in your shared assembly folder as well. This will be really helpful if your assembly is used with multiple applications so that if they fail to locate an assembly in the appbase or privatepath’s then they start looking for it in your ‘bin’ folder. This prevents you from frequently installing and uninstalling the assembly to GAC for testing purpose.
This is exactly what DEVPATH environment variable does.
How to set DEVPATH
Following example shows you how to setup just need to set assembly look up path to this variable. For e.g.
set DEVPATH=”c:\sharedassemblies\”
To enable DEVPATH look up you’ll also need to modify machine.config file, in my case its located here: C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
So next time when application runs and starts looking for your assembly it will for sure look in the above path. If fusion logger is enabled and if you open the log file for your assembly you should see something like this…
=== LOG: This bind starts in default load context. LOG: Using application configuration file: C:\myapp.exe.Config LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Found assembly in DEVOVERRIDE path C:\sharedassemblies\Test.DLL
Recently had a customer who asked this question and this looks like to have helped them so thought of sharing this out with you folks as well.
Watch outs
Please be very aware that you’ve set this feature on. You could end up having erratic behavior if somehow DEVPATH has a path containing unsupported path chars like parentheses or if DEVPATH is set to empty.
Please only use this feature in development environments as this feature by passes all normal assembly lookup features as fusion looks up DEVPATH first if enabled.
Please note fusion will look up DEVPATH as if its an AppBase folder so be aware that it will look up subdirectories as well in this DEVPATH. Also all valid assembly name look ups will be done, for e.g. .dll, .exe etc.
Do you run into following error when trying to run a VS2013 .net application on Windows XP?
Error: Not a valid Win32 application!
This happens because the application is targeting .net framework 4.5 which is not supported on Windows XP. Target a lower framework to get your application working on XP.
A date and time format string defines the text representation of a DateTime or DateTimeOffset value that results from a formatting operation . It can also define the representation of a date and time value that is required in a parsing operation in order to successfully convert the string to a date and time. A custom format string consists of one or more custom date and time format specifiers. Any string that is not a standard date and time format string is interpreted as a custom date and time format string.
Custom date and time format strings can be used with both DateTime and DateTimeOffset values.
Issue with DateTime Custom Formatters?
Recently a customer opened a ticket thinking that there is an issue with the DateTime Custom Formatters. They had following piece of code.
So what’s going wrong here with DateTime Custom Formatters
The issue here is that dt.ToString(“f”) is not recognized as a custom format specifier. Please read below documentation from MSDN…
A custom date and time format string consists of two or more characters. Date and time formatting methods interpret any single-character string as a standard date and time format string. If they do not recognize the character as a valid format specifier, they throw a FormatException. For example, a format string that consists only of the specifier “h” is interpreted as a standard date and time format string. However, in this particular case, an exception is thrown because there is no “h” standard date and time format specifier.
To use any of the custom date and time format specifiers as the only specifier in a format string (that is, to use the “d”, “f”, “F”, “g”, “h”, “H”, “K”, “m”, “M”, “s”, “t”, “y”, “z”, “:”, or “/” custom format specifier by itself), include a space before or after the specifier, or include a percent (“%”) format specifier before the single custom date and time specifier.
For example, “%h” is interpreted as a custom date and time format string that displays the hour represented by the current date and time value. You can also use the ” h” or “h ” format string, although this includes a space in the result string along with the hour. The following example illustrates these three format strings.
Resolution
So in this case the date time formatting method is interpreting this single character string as a standard date and time format string. To work around this, following are the options that you have…
1. Use dt.ToString(“%f”)
2. Use dt.ToString(“ f”);// add a space before ‘f’
3. Use dt.ToString(“f ”);// add a space after ‘f’
Yes there is a System.Configuration.ConfigurationErrorsException.
Callstack is as follows…
0:000> !pe 02fcce20
Exception object: 02fcce20
Exception type: System.Configuration.ConfigurationErrorsException
Message: An error occurred creating the configuration section handler for dataConfiguration: That assembly does not allow partially trusted callers.
InnerException: System.Security.SecurityException, Use !PrintException 02fc55d0 to see more.
StackTrace (generated):
SP IP Function
0045E2EC 69D2E834 System_Configuration_ni!System.Configuration.BaseConfigurationRecord.EvaluateOne(System.String[], System.Configuration.SectionInput, Boolean, System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object)+0xc8
0045E3C8 69D2E655 System_Configuration_ni!System.Configuration.BaseConfigurationRecord.Evaluate(System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object, Boolean, Boolean, System.Object ByRef, System.Object ByRef)+0x481
0045E488 69D26F5D System_Configuration_ni!System.Configuration.BaseConfigurationRecord.GetSectionRecursive(System.String, Boolean, Boolean, Boolean, Boolean, System.Object ByRef, System.Object ByRef)+0x5bd
0045E510 69D26F5D System_Configuration_ni!System.Configuration.BaseConfigurationRecord.GetSectionRecursive(System.String, Boolean, Boolean, Boolean, Boolean, System.Object ByRef, System.Object ByRef)+0x5bd
0045E598 69D26F5D System_Configuration_ni!System.Configuration.BaseConfigurationRecord.GetSectionRecursive(System.String, Boolean, Boolean, Boolean, Boolean, System.Object ByRef, System.Object ByRef)+0x5bd
0045E620 69D2698A System_Configuration_ni!System.Configuration.BaseConfigurationRecord.GetSection(System.String)+0x2a
0045E630 69D2A5A9 System_Configuration_ni!System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(System.String)+0x55
0045E644 69D210BF System_Configuration_ni!System.Configuration.ConfigurationManager.GetSection(System.String)+0x4f
There is an inner exception as well…
0:000> !PrintException 02fc55d0
Exception object: 02fc55d0
Exception type: System.Security.SecurityException
Message: That assembly does not allow partially trusted callers.
InnerException:
StackTrace (generated):
SP IP Function
0045DC8C 6BD56349 mscorlib_ni!System.Security.CodeAccessSecurityEngine.ThrowSecurityException(System.Reflection.RuntimeAssembly, System.Security.PermissionSet, System.Security.PermissionSet, System.RuntimeMethodHandleInternal, System.Security.Permissions.SecurityAction, System.Object, System.Security.IPermission)+0xa9
0045E1EC 6B7E9EF2 mscorlib_ni!System.RuntimeMethodHandle.PerformSecurityCheck(System.Object, System.IRuntimeMethodInfo, System.RuntimeType, UInt32)+0x22
0045E208 6B772242 mscorlib_ni!System.Reflection.RuntimeConstructorInfo.Invoke(System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)+0x82
0045E298 6B7E9EBA mscorlib_ni!System.Reflection.ConstructorInfo.Invoke(System.Object[])+0x12
0045E2A0 69D277C8 System_Configuration_ni!System.Configuration.TypeUtil.InvokeCtorWithReflectionPermission(System.Reflection.ConstructorInfo)+0x24
0045E2B0 69D276AC System_Configuration_ni!System.Configuration.RuntimeConfigurationRecord+RuntimeConfigurationFactory.CreateSectionImpl(System.Configuration.RuntimeConfigurationRecord, System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object, System.Configuration.ConfigXmlReader)+0x2c
0045E2D8 69D312DB System_Configuration_ni!System.Configuration.RuntimeConfigurationRecord+RuntimeConfigurationFactory.CreateSectionWithRestrictedPermissions(System.Configuration.RuntimeConfigurationRecord, System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object, System.Configuration.ConfigXmlReader)+0x57
0045E31C 69D2762A System_Configuration_ni!System.Configuration.RuntimeConfigurationRecord.CreateSection(Boolean, System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object, System.Configuration.ConfigXmlReader)+0x5e
0045E344 69D274E4 System_Configuration_ni!System.Configuration.BaseConfigurationRecord.CallCreateSection(Boolean, System.Configuration.FactoryRecord, System.Configuration.SectionRecord, System.Object, System.Configuration.ConfigXmlReader, System.String, Int32)+0x4c
StackTraceString:
HResult: 8013150a
SecurityException Message:
The action that failed was:
LinkDemand
The assembly or AppDomain that failed was:
System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
The Zone of the assembly that failed was:
MyComputer
The Url of the assembly that failed was:
file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
Hmm weird that the assembly having this issue is System.Configuration! CLR version is 4.0. Caspol shouldn’t kick in if that’s the case. Eventually this turned out to be a bug.
This is fixed via a hotfix: http://support.microsoft.com/kb/2580188
FIX: System.Security.SecurityException occurs when a .NET Framework 4-based application that calls a static method in the System.Configuration.ConfigurationManager class runs on a network share.
The KB article says the following…
The application calls a static method in the System.Configuration.ConfigurationManager class. For example, the application calls the ConfigurationManager.GetSection method.
For this case this was true and the application was indeed calling ConfigurationManager.GetSection.
Disclaimer:
————–
Please read through the hotfix to be very sure that this hotfix applies to you. A classic symptom would be .net 4.0 + ConfigurationManager.GetSection call.
DataRepeater is great control to display data from a table/view, as the name says repeats bunch of fields from a dataset on every row. Follow these simple steps to get started working with this control…
Make sure you’ve got the datasets in place: Press Shift + Alt + D or View –> Other Windows –> Data Sources. See below screenshots of my Northwind dataset…
Step 3:
Drag and drop an instance of data repeater onto your win forms or a container control. Resultant form will look as follows…
Please note you’ve got to have the right version of DataRepeater in order for it to get displayed on the form designer surface.
Step 4:
Drag and drop fields from your data set onto this data repeater’s surface. Note that every field dropped on to data repeater will be a pair of control (Label followed by text field or any other control if the option is provided, in my case picture control). I’ve got the following fields dropped on to the control…
The size of the control at runtime will be the same as the one you’ve given on the designer, unless you’ve docked the control. Scrollbar’s will be provided by the control to scroll through the rows of data.
Step 5:
Now if I run the form this is what I see. You can scroll through as well. Quick way to display data on a form.
Step 6:
DataRepeater supports some other features as well, please go through the documentation to know more. Enjoy!
I’ve got a native console application which would like to interop into a piece of managed code written in C#. This is the how the C# function “Sum” looks like…
My solution explorer looks as follows…
CSharpModule is a CSharp library while TestManagedCall is a native/unmanaged project. My requirement is as follows: call Class1.Sum from TestManagedCall project.
Adding Reference for Interop
To do this we’ll need to first add a reference of CSharpModule to TestManagedCall project. Go to project properties of TestManagedCall project and add a reference to CSharpModule project, see below screenshot…
So the reference of CSharpModule is now added to TestManagedCall project.
Project changes for enabling Interop
Next step is to add a new C++ file to TestManagedCall project. I’ll call the file: CSharpModuleWrapper.cpp, this class will act as a wrapper to our managed library: CSharpModule. This is how my solution will explorer look now…
Right click on CSharpModuleWrapper.cpp in the solution explorer, select properties, and enable CLR forjust this one file…
Fixing incompatibilities
Click “Ok”. Now do a full rebuild. You should see following errors pop up, fix them one by one since adding CLR support results in these incompatibilities… (you’ll see these errors popup one by one, so fixing one will lead to another. Keep fixing them and you’ll see the next error).
cl : Command line error D8016: ‘/ZI’ and ‘/clr’ command-line options are incompatible. Open the file’s(CSharpModuleWrapper.cpp) properties and go to “All Options” under C/C++ node. This is a cool feature to quickly search for an option the properties dialog. Search for /ZI as given in the above error message. CLR compilation doesn’t support /ZI change it to /Zi.
cl : Command line error D8016: ‘/clr’ and ‘/Gm’ command-line options are incompatible. Again open file’s properties and goto “All Options” under C/C++ node. Search for /Gm as given in the above message… (disable minimal rebuild). Change to /Gm-
cl : Command line error D8016: ‘/clr’ and ‘/EHs’ command-line options are incompatible. In file’s properties search for /EHs. Switch to /EHa.
cl : Command line error D8016: ‘/clr’ and ‘/RTC1’ command-line options are incompatible. Change to Default as shown below…
Disable pre-compiled headers as shown below, search for /Yu under “C/C++->All options”…
With these changes your code will compile. I get following output…
Code Changes for Interop
Now add code to use the CSharpModule’s namespace and add a function to CSharpModuleWrapper class. Eventually this is how my code will look like with all the modifications…
The CSharpModuleWrapper.h has only one change, I added a declaration for Call_Sum().
Don’t forget to call Call_Sum(). This is how the calling code looks like…
Output…
This is a reliable way to make calls into managed world from native world. Of course there are #pragma’s (managed/unmanaged) that you can use but I’m not so confident about using them. This is clean!
Conclusion
The sample I’ve shown is a ‘very’ simple one, I’m sure you’ll have a variety of requirements, let me know if I can help.
Add
Adds two values and pushes the result onto the evaluation stack.
Add_Ovf
Adds two integers, performs an overflow check, and pushes the result onto the evaluation stack.
Add_Ovf_Un
Adds two unsigned integer values, performs an overflow check, and pushes the result onto the evaluation stack.
And
Computes the bitwise AND of two values and pushes the result onto the evaluation stack.
Arglist
Returns an unmanaged pointer to the argument list of the current method.
Beq
Transfers control to a target instruction if two values are equal.
Beq_S
Transfers control to a target instruction (short form) if two values are equal.
Bge
Transfers control to a target instruction if the first value is greater than or equal to the second value.
Bge_S
Transfers control to a target instruction (short form) if the first value is greater than or equal to the second value.
Bge_Un
Transfers control to a target instruction if the first value is greater than the second value, when comparing unsigned integer values or unordered float values.
Bge_Un_S
Transfers control to a target instruction (short form) if the first value is greater than the second value, when comparing unsigned integer values or unordered float values.
Bgt
Transfers control to a target instruction if the first value is greater than the second value.
Bgt_S
Transfers control to a target instruction (short form) if the first value is greater than the second value.
Bgt_Un
Transfers control to a target instruction if the first value is greater than the second value, when comparing unsigned integer values or unordered float values.
Bgt_Un_S
Transfers control to a target instruction (short form) if the first value is greater than the second value, when comparing unsigned integer values or unordered float values.
Ble
Transfers control to a target instruction if the first value is less than or equal to the second value.
Ble_S
Transfers control to a target instruction (short form) if the first value is less than or equal to the second value.
Ble_Un
Transfers control to a target instruction if the first value is less than or equal to the second value, when comparing unsigned integer values or unordered float values.
Ble_Un_S
Transfers control to a target instruction (short form) if the first value is less than or equal to the second value, when comparing unsigned integer values or unordered float values.
Blt
Transfers control to a target instruction if the first value is less than the second value.
Blt_S
Transfers control to a target instruction (short form) if the first value is less than the second value.
Blt_Un
Transfers control to a target instruction if the first value is less than the second value, when comparing unsigned integer values or unordered float values.
Blt_Un_S
Transfers control to a target instruction (short form) if the first value is less than the second value, when comparing unsigned integer values or unordered float values.
Bne_Un
Transfers control to a target instruction when two unsigned integer values or unordered float values are not equal.
Bne_Un_S
Transfers control to a target instruction (short form) when two unsigned integer values or unordered float values are not equal.
Box
Converts a value type to an object reference (type O).
Br
Unconditionally transfers control to a target instruction.
Br_S
Unconditionally transfers control to a target instruction (short form).
Break
Signals the Common Language Infrastructure (CLI) to inform the debugger that a break point has been tripped.
Brfalse
Transfers control to a target instruction if value is false, a null reference (Nothing in Visual Basic), or zero.
Brfalse_S
Transfers control to a target instruction if value is false, a null reference, or zero.
Brtrue
Transfers control to a target instruction if value is true, not null, or non-zero.
Brtrue_S
Transfers control to a target instruction (short form) if value is true, not null, or non-zero.
Call
Calls the method indicated by the passed method descriptor.
Calli
Calls the method indicated on the evaluation stack (as a pointer to an entry point) with arguments described by a calling convention.
Callvirt
Calls a late-bound method on an object, pushing the return value onto the evaluation stack.
Castclass
Attempts to cast an object passed by reference to the specified class.
Ceq
Compares two values. If they are equal, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.
Cgt
Compares two values. If the first value is greater than the second, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.
Cgt_Un
Compares two unsigned or unordered values. If the first value is greater than the second, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.
Clt
Compares two values. If the first value is less than the second, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.
Clt_Un
Compares the unsigned or unordered values value1 and value2. If value1 is less than value2, then the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.
Constrained
Constrains the type on which a virtual method call is made.
Conv_I
Converts the value on top of the evaluation stack to native int.
Conv_I1
Converts the value on top of the evaluation stack to int8, then extends (pads) it to int32.
Conv_I2
Converts the value on top of the evaluation stack to int16, then extends (pads) it to int32.
Conv_I4
Converts the value on top of the evaluation stack to int32.
Conv_I8
Converts the value on top of the evaluation stack to int64.
Conv_Ovf_I
Converts the signed value on top of the evaluation stack to signed native int, throwing OverflowException on overflow.
Conv_Ovf_I_Un
Converts the unsigned value on top of the evaluation stack to signed native int, throwing OverflowException on overflow.
Conv_Ovf_I1
Converts the signed value on top of the evaluation stack to signed int8 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_I1_Un
Converts the unsigned value on top of the evaluation stack to signed int8 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_I2
Converts the signed value on top of the evaluation stack to signed int16 and extending it to int32, throwing OverflowException on overflow.
Conv_Ovf_I2_Un
Converts the unsigned value on top of the evaluation stack to signed int16 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_I4
Converts the signed value on top of the evaluation stack to signed int32, throwing OverflowException on overflow.
Conv_Ovf_I4_Un
Converts the unsigned value on top of the evaluation stack to signed int32, throwing OverflowException on overflow.
Conv_Ovf_I8
Converts the signed value on top of the evaluation stack to signed int64, throwing OverflowException on overflow.
Conv_Ovf_I8_Un
Converts the unsigned value on top of the evaluation stack to signed int64, throwing OverflowException on overflow.
Conv_Ovf_U
Converts the signed value on top of the evaluation stack to unsigned native int, throwing OverflowException on overflow.
Conv_Ovf_U_Un
Converts the unsigned value on top of the evaluation stack to unsigned native int, throwing OverflowException on overflow.
Conv_Ovf_U1
Converts the signed value on top of the evaluation stack to unsigned int8 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_U1_Un
Converts the unsigned value on top of the evaluation stack to unsigned int8 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_U2
Converts the signed value on top of the evaluation stack to unsigned int16 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_U2_Un
Converts the unsigned value on top of the evaluation stack to unsigned int16 and extends it to int32, throwing OverflowException on overflow.
Conv_Ovf_U4
Converts the signed value on top of the evaluation stack to unsigned int32, throwing OverflowException on overflow.
Conv_Ovf_U4_Un
Converts the unsigned value on top of the evaluation stack to unsigned int32, throwing OverflowException on overflow.
Conv_Ovf_U8
Converts the signed value on top of the evaluation stack to unsigned int64, throwing OverflowException on overflow.
Conv_Ovf_U8_Un
Converts the unsigned value on top of the evaluation stack to unsigned int64, throwing OverflowException on overflow.
Conv_R_Un
Converts the unsigned integer value on top of the evaluation stack to float32.
Conv_R4
Converts the value on top of the evaluation stack to float32.
Conv_R8
Converts the value on top of the evaluation stack to float64.
Conv_U
Converts the value on top of the evaluation stack to unsigned native int, and extends it to native int.
Conv_U1
Converts the value on top of the evaluation stack to unsigned int8, and extends it to int32.
Conv_U2
Converts the value on top of the evaluation stack to unsigned int16, and extends it to int32.
Conv_U4
Converts the value on top of the evaluation stack to unsigned int32, and extends it to int32.
Conv_U8
Converts the value on top of the evaluation stack to unsigned int64, and extends it to int64.
Cpblk
Copies a specified number bytes from a source address to a destination address.
Cpobj
Copies the value type located at the address of an object (type &, * or native int) to the address of the destination object (type &, * or native int).
Div
Divides two values and pushes the result as a floating-point (type F) or quotient (type int32) onto the evaluation stack.
Div_Un
Divides two unsigned integer values and pushes the result (int32) onto the evaluation stack.
Dup
Copies the current topmost value on the evaluation stack, and then pushes the copy onto the evaluation stack.
Endfilter
Transfers control from the filter clause of an exception back to the Common Language Infrastructure (CLI) exception handler.
Endfinally
Transfers control from the fault or finally clause of an exception block back to the Common Language Infrastructure (CLI) exception handler.
Initblk
Initializes a specified block of memory at a specific address to a given size and initial value.
Initobj
Initializes each field of the value type at a specified address to a null reference or a 0 of the appropriate primitive type.
Isinst
Tests whether an object reference (type O) is an instance of a particular class.
Jmp
Exits current method and jumps to specified method.
Ldarg
Loads an argument (referenced by a specified index value) onto the stack.
Ldarg_0
Loads the argument at index 0 onto the evaluation stack.
Ldarg_1
Loads the argument at index 1 onto the evaluation stack.
Ldarg_2
Loads the argument at index 2 onto the evaluation stack.
Ldarg_3
Loads the argument at index 3 onto the evaluation stack.
Ldarg_S
Loads the argument (referenced by a specified short form index) onto the evaluation stack.
Ldarga
Load an argument address onto the evaluation stack.
Ldarga_S
Load an argument address, in short form, onto the evaluation stack.
Ldc_I4
Pushes a supplied value of type int32 onto the evaluation stack as an int32.
Ldc_I4_0
Pushes the integer value of 0 onto the evaluation stack as an int32.
Ldc_I4_1
Pushes the integer value of 1 onto the evaluation stack as an int32.
Ldc_I4_2
Pushes the integer value of 2 onto the evaluation stack as an int32.
Ldc_I4_3
Pushes the integer value of 3 onto the evaluation stack as an int32.
Ldc_I4_4
Pushes the integer value of 4 onto the evaluation stack as an int32.
Ldc_I4_5
Pushes the integer value of 5 onto the evaluation stack as an int32.
Ldc_I4_6
Pushes the integer value of 6 onto the evaluation stack as an int32.
Ldc_I4_7
Pushes the integer value of 7 onto the evaluation stack as an int32.
Ldc_I4_8
Pushes the integer value of 8 onto the evaluation stack as an int32.
Ldc_I4_M1
Pushes the integer value of -1 onto the evaluation stack as an int32.
Ldc_I4_S
Pushes the supplied int8 value onto the evaluation stack as an int32, short form.
Ldc_I8
Pushes a supplied value of type int64 onto the evaluation stack as an int64.
Ldc_R4
Pushes a supplied value of type float32 onto the evaluation stack as type F (float).
Ldc_R8
Pushes a supplied value of type float64 onto the evaluation stack as type F (float).
Ldelem
Loads the element at a specified array index onto the top of the evaluation stack as the type specified in the instruction.
Ldelem_I
Loads the element with type native int at a specified array index onto the top of the evaluation stack as a native int.
Ldelem_I1
Loads the element with type int8 at a specified array index onto the top of the evaluation stack as an int32.
Ldelem_I2
Loads the element with type int16 at a specified array index onto the top of the evaluation stack as an int32.
Ldelem_I4
Loads the element with type int32 at a specified array index onto the top of the evaluation stack as an int32.
Ldelem_I8
Loads the element with type int64 at a specified array index onto the top of the evaluation stack as an int64.
Ldelem_R4
Loads the element with type float32 at a specified array index onto the top of the evaluation stack as type F (float).
Ldelem_R8
Loads the element with type float64 at a specified array index onto the top of the evaluation stack as type F (float).
Ldelem_Ref
Loads the element containing an object reference at a specified array index onto the top of the evaluation stack as type O (object reference).
Ldelem_U1
Loads the element with type unsigned int8 at a specified array index onto the top of the evaluation stack as an int32.
Ldelem_U2
Loads the element with type unsigned int16 at a specified array index onto the top of the evaluation stack as an int32.
Ldelem_U4
Loads the element with type unsigned int32 at a specified array index onto the top of the evaluation stack as an int32.
Ldelema
Loads the address of the array element at a specified array index onto the top of the evaluation stack as type & (managed pointer).
Ldfld
Finds the value of a field in the object whose reference is currently on the evaluation stack.
Ldflda
Finds the address of a field in the object whose reference is currently on the evaluation stack.
Ldftn
Pushes an unmanaged pointer (type native int) to the native code implementing a specific method onto the evaluation stack.
Ldind_I
Loads a value of type native int as a native int onto the evaluation stack indirectly.
Ldind_I1
Loads a value of type int8 as an int32 onto the evaluation stack indirectly.
Ldind_I2
Loads a value of type int16 as an int32 onto the evaluation stack indirectly.
Ldind_I4
Loads a value of type int32 as an int32 onto the evaluation stack indirectly.
Ldind_I8
Loads a value of type int64 as an int64 onto the evaluation stack indirectly.
Ldind_R4
Loads a value of type float32 as a type F (float) onto the evaluation stack indirectly.
Ldind_R8
Loads a value of type float64 as a type F (float) onto the evaluation stack indirectly.
Ldind_Ref
Loads an object reference as a type O (object reference) onto the evaluation stack indirectly.
Ldind_U1
Loads a value of type unsigned int8 as an int32 onto the evaluation stack indirectly.
Ldind_U2
Loads a value of type unsigned int16 as an int32 onto the evaluation stack indirectly.
Ldind_U4
Loads a value of type unsigned int32 as an int32 onto the evaluation stack indirectly.
Ldlen
Pushes the number of elements of a zero-based, one-dimensional array onto the evaluation stack.
Ldloc
Loads the local variable at a specific index onto the evaluation stack.
Ldloc_0
Loads the local variable at index 0 onto the evaluation stack.
Ldloc_1
Loads the local variable at index 1 onto the evaluation stack.
Ldloc_2
Loads the local variable at index 2 onto the evaluation stack.
Ldloc_3
Loads the local variable at index 3 onto the evaluation stack.
Ldloc_S
Loads the local variable at a specific index onto the evaluation stack, short form.
Ldloca
Loads the address of the local variable at a specific index onto the evaluation stack.
Ldloca_S
Loads the address of the local variable at a specific index onto the evaluation stack, short form.
Ldnull
Pushes a null reference (type O) onto the evaluation stack.
Ldobj
Copies the value type object pointed to by an address to the top of the evaluation stack.
Ldsfld
Pushes the value of a static field onto the evaluation stack.
Ldsflda
Pushes the address of a static field onto the evaluation stack.
Ldstr
Pushes a new object reference to a string literal stored in the metadata.
Ldtoken
Converts a metadata token to its runtime representation, pushing it onto the evaluation stack.
Ldvirtftn
Pushes an unmanaged pointer (type native int) to the native code implementing a particular virtual method associated with a specified object onto the evaluation stack.
Leave
Exits a protected region of code, unconditionally transferring control to a specific target instruction.
Leave_S
Exits a protected region of code, unconditionally transferring control to a target instruction (short form).
Localloc
Allocates a certain number of bytes from the local dynamic memory pool and pushes the address (a transient pointer, type *) of the first allocated byte onto the evaluation stack.
Mkrefany
Pushes a typed reference to an instance of a specific type onto the evaluation stack.
Mul
Multiplies two values and pushes the result on the evaluation stack.
Mul_Ovf
Multiplies two integer values, performs an overflow check, and pushes the result onto the evaluation stack.
Mul_Ovf_Un
Multiplies two unsigned integer values, performs an overflow check, and pushes the result onto the evaluation stack.
Neg
Negates a value and pushes the result onto the evaluation stack.
Newarr
Pushes an object reference to a new zero-based, one-dimensional array whose elements are of a specific type onto the evaluation stack.
Newobj
Creates a new object or a new instance of a value type, pushing an object reference (type O) onto the evaluation stack.
Nop
Fills space if opcodes are patched. No meaningful operation is performed although a processing cycle can be consumed.
Not
Computes the bitwise complement of the integer value on top of the stack and pushes the result onto the evaluation stack as the same type.
Or
Compute the bitwise complement of the two integer values on top of the stack and pushes the result onto the evaluation stack.
Pop
Removes the value currently on top of the evaluation stack.
Prefix1
Infrastructure. This is a reserved instruction.
Prefix2
Infrastructure. This is a reserved instruction.
Prefix3
Infrastructure. This is a reserved instruction.
Prefix4
Infrastructure. This is a reserved instruction.
Prefix5
Infrastructure. This is a reserved instruction.
Prefix6
Infrastructure. This is a reserved instruction.
Prefix7
Infrastructure. This is a reserved instruction.
Prefixref
Infrastructure. This is a reserved instruction.
Readonly
Specifies that the subsequent array address operation performs no type check at run time, and that it returns a managed pointer whose mutability is restricted.
Refanytype
Retrieves the type token embedded in a typed reference.
Refanyval
Retrieves the address (type &) embedded in a typed reference.
Rem
Divides two values and pushes the remainder onto the evaluation stack.
Rem_Un
Divides two unsigned values and pushes the remainder onto the evaluation stack.
Ret
Returns from the current method, pushing a return value (if present) from the callee’s evaluation stack onto the caller’s evaluation stack.
Tailcall
Performs a postfixed method call instruction such that the current method’s stack frame is removed before the actual call instruction is executed.
Throw
Throws the exception object currently on the evaluation stack.
Unaligned
Indicates that an address currently atop the evaluation stack might not be aligned to the natural size of the immediately following ldind, stind, ldfld, stfld, ldobj, stobj, initblk, or cpblk instruction.
Unbox
Converts the boxed representation of a value type to its unboxed form.
Unbox_Any
Converts the boxed representation of a type specified in the instruction to its unboxed form.
Volatile
Specifies that an address currently atop the evaluation stack might be volatile, and the results of reading that location cannot be cached or that multiple stores to that location cannot be suppressed.
Xor
Computes the bitwise XOR of the top two values on the evaluation stack, pushing the result onto the evaluation stack.
Please note that this post is only applicable for .net 4.5 and above.
Having trouble with .net array size limit, i.e. 2GB on a 64 bit target. Use gcAllowVeryLargeObjects tag in application config file to work around this issue. A sample config file will look as follows…
Please read the docs very carefully, there are some caveats that you should be aware off… (from MSDN)
Using this element in your application configuration file enables arrays that are larger than 2 GB in size, but does not change other limits on object size or array size:
The maximum number of elements in an array is UInt32.MaxValue.
The maximum index in any single dimension is 2,147,483,591 (0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and 2,146,435,071 (0X7FEFFFFF) for other types.
The maximum size for strings and other non-array objects is unchanged.
Thought I will share some interesting differences between a .net class and a struct.
Class
Struct
Allocated on the heap.
Allocated on the stack. They are value types and don’t require heap allocation.
A variable of a class type stores a reference to a dynamically allocated object.
A variable of a struct type directly stores the data of the struct.
Supports user-specified inheritance.
Does not support user-specified inheritance and all struct types implicitly inherit from type object.
An array of, class Point instances of, size 100 implies 101 separate objects are instantiated. One for the array and one each for the 100 elements.
An array, of struct Point instances, of size 100 implies only one object i.e. the array is instantiated and the struct Point instances are stored inline in the array.
Dynamic allocation done via ‘new’ call.
Struct constructors are invoked with the new operator but that does not imply that memory is being allocated. Instead of dynamically allocating an object and returning a reference to it, a struct constructor simply returns the struct value itself (typically in a temporary location on the stack), and this value is then copied as necessary.
With classes, it is possible for two variables to reference the same object and thus possible for operations on one variable to affect the object referenced by the other variable.
With structs, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other. For example, the output produced by the following code fragment depends on whether Point is a class or a struct.
Classes are kind of faster as only their references are copied around.
Structs are copied by value unless we specify ref, out parameters hence the copying overhead is there.
Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. The use of structs rather than classes for small data structures can make a large difference in the number of memory allocations an application performs.
These differences are picked up from the C# 4.0 language specification.