FatalExecutionEngineError during C# Marshalling - c#

I'm running into an issue when trying to read c++ structures from memofields in a number of DBase IV files into C# (.Net 4) and then insert them into MSSQL 2008. The data is being extracted ok from the DBase files but I seemed to be doing something wrong with managing the unsafe calls because I randomly get the following error:
FatalExecutionEngineError was detected
Message: The runtime has encountered a fatal error. The address of the error was
at 0x791fa62c, on thread 0x16c0. The error code is 0xc0000005. This error may be
a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.
The following is the code I use to read the data. This code completes successfully and the data I get from the files are correct. The error occurs a number of minutes after this function is called, when the objects are being inserted into the database using nhibernate (I left it out because I didn't think it really matter to the issue).
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Event
{
public int Number;
public int Month;
public int Day;
public int Year;
public int Hour;
public int Minute;
public int Second;
public UInt32 UPCTime;
public int BlobSize;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = DataLengths.MAX_EVENT_TITLE_LENGTH)]
public string Title;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = DataLengths.MAX_TRIGGER_LENGTH)]
public string Trigger;
}
public struct Trigger
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Control;
public int Index;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Mode;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string RecordFreq;
public int Pre;
public int Post;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Source;
public int Delay;
public int EventUserNotify;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public int[] Spare;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DataLengths.MAX_EVENT_SENSORS)]
public int[] Sensors;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Value
{
public Trigger Trigger;
public string[] SensorLabels;
public Point[] Point;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Point
{
public Single Value;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string State;
}
//The dbf is from the java xBasej library that I compiled into a dll using IKVM.net
public Dictionary<Event, Value> Read(DBF dbf)
{
Dictionary<Event, Value> eventData = new Dictionary<Event, Value>();
try
{
for (int i = 1; i <= dbf.getRecordCount(); i++)
{
dbf.gotoRecord(i);
MemoField memofield = (MemoField)dbf.getField("MemoField");
// Perform the conversion from one encoding to the other.
byte[] blob = memofield.getBytes();
if (blob.Length == 0)
{
continue;
}
MemoryStream memoryStream = null;
BinaryReader binaryReader = null;
GCHandle eventHandle = new GCHandle();
GCHandle triggerHandle = new GCHandle();
GCHandle sensorLabelHandle = new GCHandle();
GCHandle pointHandle = new GCHandle();
try
{
memoryStream = new MemoryStream(blob);
binaryReader = new BinaryReader(memoryStream);
//The data was orignally C++ structures so we read the bytes back into C# equivalent
//structures.
int eventDataSize = Marshal.SizeOf(typeof(Event));
eventHandle = GCHandle.Alloc(binaryReader.ReadBytes(eventDataSize), GCHandleType.Pinned);
Event #event = (Event)Marshal.PtrToStructure(eventHandle.AddrOfPinnedObject(), typeof(Event));
//Read the event trigger data
int triggerDataSize = Marshal.SizeOf(typeof(Trigger));
triggerHandle = GCHandle.Alloc(binaryReader.ReadBytes(triggerDataSize), GCHandleType.Pinned);
Trigger trigger = (Trigger)Marshal.PtrToStructure(triggerHandle.AddrOfPinnedObject(), typeof(Trigger));
Value value = new Value();
value.Trigger = trigger;
triggerHandle.Free();
//Read all the sensor labels
List<string> sensorLableList = new List<string>();
for (int sensorIndex = 0; sensorIndex < DataLengths.MAX_EVENT_SENSORS; sensorIndex++)
{
int sensorLableDataSize = DataLengths.MAX_LABEL_LENGTH;
sensorLabelHandle = GCHandle.Alloc(binaryReader.ReadBytes(sensorLableDataSize), GCHandleType.Pinned);
string label = Marshal.PtrToStringAnsi(sensorLabelHandle.AddrOfPinnedObject(), sensorLableDataSize).Trim();
sensorLableList.Add(label);
sensorLabelHandle.Free();
}
value.SensorLabels = sensorLableList.ToArray();
//Read all the recorded sensor data
List<Point> pointList = new List<Point>();
for (int pointIndex = 0; pointIndex < DataLengths.MAX_EVENT_SENSORS; pointIndex++)
{
int pointDataSize = Marshal.SizeOf(typeof(Point));
pointHandle = GCHandle.Alloc(binaryReader.ReadBytes(pointDataSize), GCHandleType.Pinned);
Point point = (Point)Marshal.PtrToStructure(pointHandle.AddrOfPinnedObject(), typeof(Point));
pointList.Add(point);
pointHandle.Free();
}
value.Point = pointList.ToArray();
eventData.Add(#event, value);
eventHandle.Free();
}
finally
{
//Free all the resources used to get the data
if (memoryStream != null) { memoryStream.Close(); }
if (binaryReader != null) { binaryReader.Close(); }
if (eventHandle.IsAllocated) { eventHandle.Free(); }
if (triggerHandle.IsAllocated) { triggerHandle.Free(); }
if (sensorLabelHandle.IsAllocated) { sensorLabelHandle.Free(); }
if (pointHandle.IsAllocated) { pointHandle.Free(); }
GC.Collect();
}
}
}
finally
{
if (dbf != null)
{
dbf.close();
}
}
return eventData;
}

Interesting failure mode, this is not supposed to happen. You get the FEEE typically because the garbage collected heap is getting destroyed. This is normally easily explained by a misbehaving pinvoked native function that does something like overflow a buffer. No pinvoke here though.
There's however an excellent candidate for this mishap:
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Control;
The marshaling for this is designed to marshal a C string, a zero-terminated array of characters. A SizeConst = 1 cannot work properly by design, that only leaves room for the zero terminator, not any character. On top of which, a .dbf file doesn't contain zero terminated strings, they are fixed-width according to the field declaration.
Whether the access violation is actually caused by the marshaller getting this wrong is an open question though, it can just as easily bomb on trying to find the zero terminator. Not find one and blunder into an unmapped memory page.
Anyhoo, you're doing it wrong. You must use a char[] instead of a string in the structure declaration and use ByValArray in the [MarshalAs] attribute. Pretty painful coding btw.

Within your Trigger structure, are you sure you have the right packing? It looks like the Index member would be at offset 4 where as you might have intended it to be at offset 1? Same with Pre and Post.
Also, what size is Control supposed to be? If it is a string, usually unmanaged strings are null-terminated. By specifying the length of 1, that would indicate to me a single character. If that is the case, why not use char for it instead of string?
Error 0xc0000005 is an access violation.
Have you tried running under the debugger and enabling unmanaged code debugging? You can then set the access violation to be caught right when thrown as it might be happening inside .NET framework code. You then could look at memory and get an idea of what it might be doing.

Related

Unmarhsalling array of pointer of structure

I have a requirement to connect to a third party application with a C interface, but I everything I tried so far, crashes the application while working with the ImageArray.images field.
One of its methods requires an structure declared as:
typedef struct {
int size;
Image **images;
} ImageArray;
The Image type is a simple structure, with only int fields (like width and height):
typedef struct {
int width;
int height;
} Image;
An image may be accessed first derefencing the array element, than dereferencing the Image struct. For example:
ImageArray imageArray = ... // initialize it somehow.
imageArray[0]->width
The function I'm trying to call from C# without success is declared as:
int Segment(Image *image, ImageArray **images);
So far, I've declared the following structures and methods to interface with the native library:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct Image
{
public int Width;
public int Height;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal unsafe struct ImageArray
{
public Int32 Size;
public IntPtr Images;
}
public static extern int Segment([In] ref Image image, [Out] out IntPtr images);
Also, I've implemented the following wrapper, which triggers the error:
IntPtr imagesArrayPtr;
Segment(ref nImage, out imagesArrayPtr));
var imageArray = (ImageArray)Marshal.PtrToStructure(imagesArrayPtr, typeof(ImageArray));
var sz = imageArray.Size;
var ptr = imageArray.Images;
var images = new Image[imageArray.Size];
for (var i = 0; i < imageArray.Size; i++)
{
images[i] = (Image)Marshal.PtrToStructure(ptr, typeof(Image));
ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(IntPtr)));
}
I removed the error checking to reduce the code size.
This example I came up while looking at other stack overflow questions.
How can I correctly implement this call?
Update: Calling Segment from C/C++ (error checking ommited):
Image *image;
ImageLoadFromFile("file.png", &image);
ImageArray *imageArray;
Segment(image, &imageArray);
for ( int i = 0; i < imageArray->size; i++ ) {
const Image *img = imageArray[i];
printf("width=%d height=%d\n", img->width, img->height);
}
The function ImageLoadFromFile loads the specified image at the first argument at its second argument, returning true if success (error checking ommited).

How to assign (byte* + offset) to byte[]?

I have a struct:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct FieldIndex {
public fixed byte Meta[16];
}
The first byte is TypeCode. The remaining 15 bytes is a UTF8-encoded string.
I'm using the following to fill the nameBuf byte array:
private static string GetMetaName (FieldIndex meta) {
var idx = 0;
var bytesOut = 1;
var nameBuf = new byte[Indexer.MAXFIELDNAMELENGTH]; // 15
while (bytesOut < Indexer.MAXFIELDLENGTH) { // 16
nameBuf[idx] = *(byte*)((byte*)&meta + bytesOut);
++bytesOut;
++idx;
}
//var src = (byte*)&field.meta + 1;
//fixed (byte* b = nameBuf) {
// *((byte*)b) = (byte)src;
//}
return BinaryConverter.ToString(nameBuf, 0, Indexer.MAXFIELDNAMELENGTH, Indexer.DefaultEncoding);
}
In the commented code above, I was trying to accomplish the same task without the while iteration but it does not work (no compile error, just the wrong interpolation). Can I assign nameBuf without the while-loop?
Update
I'd also prefer using the (byte*) rather than Marshal.Copy.
You could try to use the Marshal.Copy static method in unsafe context:
unsafe
{
Marshal.Copy(new IntPtr(meta), nameBuf, 1, nameBuf.Length);
}
There isn't much point in doing this the hard unsafe way when you can do it just easily this way:
[StructLayout(LayoutKind.Sequential)]
struct FieldIndex {
public byte Typecode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
private byte[] Utf8string;
public string GetString() {
return Encoding.UTF8.GetString(Utf8string, 0, 15);
}
}
No while-loop, mission accomplished. That pointer is still there and is just as efficient, you just don't see it anymore. If you fret over calling the GetString() method too often then simply declare another public class and keep this one internal.

C# Pointer: error CS0254: The right hand side of a fixed statement assignment may not be a cast expression

I have a c++ server and now a trying to make a c# client.
In c++, to send a packet I make this:
PMessage *msg = (PMessage*)&buf[0];
msg->id = PID_LOGIN;
sendto(sServer, buf, sizeof(buf), 0, (SOCKADDR*)&from, fromlen);
in c# I trying this:
unsafe
{
try
{
byte[] rawdata = new byte[Marshal.SizeOf(typeof(PMessage))];
fixed (PMessage* p = (PMessage*)&rawdata[0])
{
// p->id = 1001;
}
udpClient.Send(rawdata, rawdata.Length); ;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
The compiler show this error:
error CS0254: The right hand side of a fixed statement assignment may not be a cast expression.
c#:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct PMessage
{
public fixed byte msg[256];
public int id;
public int size;
}
c++:
struct PMessage
{
char msg[256];
unsigned int id;
unsigned int size;
};
Try this:
PMessage p = new PMessage();
// p.id = 1001;
byte[] rawdata = new byte[Marshal.SizeOf(typeof(PMessage))];
IntPtr mem = Marshal.AllocHGlobal(rawdata.Length);
try{
Marshal.StructureToPtr(p, mem, true);
Marshal.Copy(mem, rawdata, 0, rawdata.Length);
}finally{
Marshal.FreeHGlobal(mem);
}
udpClient.Send(rawdata, rawdata.Length);
Also don't mix unsafe (fixed) and unmanaged (SizeOf) environments.
You can't do this, because the compiler loses track of which object needs to be pinned.
fixed (PMessage* p = (PMessage*)&rawdata[0])
However this should work
fixed (byte* pby = &rawdata[0]) {
PMessage* p = (PMessage*)pby;
Please note that your C++ code was probably violating strict aliasing, and both C++ and C# may not have correct alignment.

How to do memcpy in C# .Net CF with the following task

Hi I am trying to convert the C/C++ Strcut to C# and how to fill the structure member with address of another structure in C#?
C/C++ Struct looks like:
typedef struct _NDISUIO_QUERY_OID
{
NDIS_OID Oid;
PTCHAR ptcDeviceName;
UCHAR Data[sizeof(ULONG)];
} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
typedef struct My_Struct
{
//les have 2 variables...
UINT a;
UINT b;
}My_STATS, *PMy_STATS;
PNDISUIO_QUERY_OID pQueryOid = NULL;
pQueryOid = (PNDISUIO_QUERY_OID)malloc(sizeof(NDISUIO_QUERY_OID)+ sizeof(My_STATS)) ;
PMy_STATS Statistics;
pQueryOid->Oid = ulOIDCode;//Required OID
pQueryOid->ptcDeviceName = AUB_NAME;//REquired STRING
memcpy(pQueryOid->Data, Statistics, sizeof(My_STATS));
My C# Struct is:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
public uint Oid;
[MarshalAs(UnmanagedType.LPWStr)]
public string ptcDeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = sizeof(uint))]
public string Data;
};
Problem: How to copy the Statistics structure to Data array in C#??
Thanks :)
Here's my implementation (FYI, the SDF contains all of this code and a lot more)
internal class NDISQueryOid
{
protected const int NDISUIO_QUERY_OID_SIZE = 12;
protected byte[] m_data;
public int Size { get; private set; }
public NDISQueryOid(byte[] data)
{
int extrasize = data.Length;
Size = 8 + extrasize;
m_data = new byte[Size];
Buffer.BlockCopy(data, 0, m_data, DataOffset, data.Length);
}
public NDISQueryOid(int extrasize)
{
Size = NDISUIO_QUERY_OID_SIZE + extrasize;
m_data = new byte[Size];
}
protected const int OidOffset = 0;
public uint Oid
{
get { return BitConverter.ToUInt32(m_data, OidOffset); }
set
{
byte[] bytes = BitConverter.GetBytes(value);
Buffer.BlockCopy(bytes, 0, m_data, OidOffset, 4);
}
}
protected const int ptcDeviceNameOffset = OidOffset + 4;
public unsafe byte* ptcDeviceName
{
get
{
return (byte*)BitConverter.ToUInt32(m_data, ptcDeviceNameOffset);
}
set
{
byte[] bytes = BitConverter.GetBytes((UInt32)value);
Buffer.BlockCopy(bytes, 0, m_data, ptcDeviceNameOffset, 4);
}
}
protected const int DataOffset = ptcDeviceNameOffset + 4;
public byte[] Data
{
get
{
byte[] b = new byte[Size - DataOffset];
Array.Copy(m_data, DataOffset, b, 0, Size - DataOffset);
return b;
}
set
{
Size = 8 + value.Length;
m_data = new byte[Size];
Buffer.BlockCopy(value, 0, m_data, DataOffset, value.Length);
}
}
public byte[] getBytes()
{
return m_data;
}
public static implicit operator byte[](NDISQueryOid qoid)
{
return qoid.m_data;
}
}
Note that in my usage, the NDIS IOCT takes in a pointer (most of my NDIS work is all done as unsafe) so you'd have to do some adjustment there.
So if, for example, you're querying the BSSID, I know the BSSID data is 36 bytes, so I'd create something like this:
var queryOID = new NDISQueryOid(36);
then allocate the name and call NDIS (the production code has a lot more checking than this):
byte[] nameBytes = System.Text.Encoding.Unicode.GetBytes(adapterName + '\0');
fixed (byte* pName = &nameBytes[0])
{
queryOID.ptcDeviceName = pName;
queryOID.Oid = (uint)oid;
var bytes = queryOID.getBytes();
ndis.DeviceIoControl(IOCTL_NDISUIO_QUERY_OID_VALUE, bytes, bytes);
var result = new byte[queryOID.Data.Length];
Buffer.BlockCopy(queryOID.Data, 0, result, 0, result.Length);
}
EDIT
So the result member above is a byte array of the "result" of the query. What it means and how you interpret it depends on what the OID you queried was. For example, if you were querying the currently connected SSID (i.e. NDIS_OID.SSID), then that comes back as a 4-byte length followed by the ASCII-encoded name, so you'd decipher it like this:
int len = BitConverter.ToInt32(data, 0);
if (len > 0)
{
ssid = System.Text.Encoding.ASCII.GetString(data, 4, len);
}
But again, this is only for one specific OID. You have to handle every return case for every incoming OID you decide to support.
First you have the wrong translation of your C++ code: the C# equivalent of a C++ char[] is not a string, it's a byte[]. Once you have that, you just need to know, in general, how to copy a structure into a byte array. Here's a compilable example:
using System;
using System.Runtime.InteropServices;
struct Dest
{
public byte[] Data;
}
struct Src
{
public GCHandle StringHandle;
public long A;
public long B;
}
class Program
{
static void Main()
{
Copy();
}
static void Copy()
{
var str = "Hello";
var src = new Src {
A = 3,
B = 4,
StringHandle = GCHandle.Alloc(str, GCHandleType.Normal)
};
var dst = new Dest();
unsafe
{
Src* srcPtr = &src;
dst.Data = new byte[sizeof(Src)];
Marshal.Copy((IntPtr)srcPtr, dst.Data, 0, sizeof(Src));
}
// When you're sure no one can reference the string anymore
// (Including by accessing the data you put in dst.Data!)
src.StringHandle.Free();
}
EDIT: added example of how to deal with reference types such as strings.
Safely, you can't. .NET enforces type safety, which means that you simply can't force a string to be a structure. However, you can look at the data instead of doing unsafe type casts (why are you storing two uints in a string in the first place? And marshalling it as unicode?
First, you'll have to make Data a byte array. It might be possible to do this with a string as well, but that's just adding encoding issues to the mix; if you can, use byte[] instead. Also, if you don't need to have different kinds of data inside (it seems so), you could simply put the two uint fields right inside the struct and it should work just fine:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
public uint Oid;
[MarshalAs(UnmanagedType.LPWStr)]
public string ptcDeviceName;
public uint DataA;
public uint DataB;
};
The second approach would use a const-sized byte array, long enough to hold the two uints:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
public uint Oid;
[MarshalAs(UnmanagedType.LPWStr)]
public string ptcDeviceName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = sizeof(ulong))]
public byte[] Data;
};
The first four bytes will be the first uint, the next will be the second.
And of course, you could also use a .NET struct the same way as in the original code - just make sure you use the correct datatype in _NDISUIO_QUERY_OID and it should work automagically.
One point to note though, it seems that the data returned isn't actually necessarily fixed-length. That is quite tricky and it basically means you'd have to deserialize the structure manually based on the pointer and length you get.

integer handle to memory address C#

My main purpose in doing this conversion is to create an object in C# based off of a memory address...would it be too hack-ish (or totally incorrect/stupid)? If so, is there a better way in doing this?
Something like this:
int app_handle = 920663024; // corresponds to memory location 0x36E033F0
string app_handle_converted_to_hex = decValue.ToString("X");
MyAppClass *newApp = (MyAppClass *)app_handle_converted_to_hex;
Also, is this possible to do at all without the use of pointers?
You're going to want to use Marshal.PtrToStructure which assumes a sequential layout.
Take a look at the example at the bottom of the page.
This code assumes 32-bit compilation. Before using a 64-bit compiler, replace IntPtr.ToInt32 with IntPtr.ToInt64.
[StructLayout(LayoutKind.Sequential)]
public class INNER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string field1 = "Test";
}
[StructLayout(LayoutKind.Sequential)]
public struct OUTER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string field1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public byte[] inner;
}
[DllImport(#"SomeTestDLL.dll")]
public static extern void CallTest( ref OUTER po);
static void Main(string[] args)
{
OUTER ed = new OUTER();
INNER[] inn = new INNER[10];
INNER test = new INNER();
int iStructSize = Marshal.SizeOf(test);
int sz =inn.Length * iStructSize;
ed.inner = new byte[sz];
try
{
CallTest( ref ed);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
IntPtr buffer = Marshal.AllocCoTaskMem(iStructSize*10);
Marshal.Copy(ed.inner,0,buffer,iStructSize*10);
int iCurOffset = 0;
for(int i = 0; i < 10; i++)
{
inn[i] = (INNER)Marshal.PtrToStructure(new IntPtr(buffer.ToInt32() + iCurOffset),typeof(INNER) );
iCurOffset += iStructSize;
}
Console.WriteLine(ed.field1);
Marshal.FreeCoTaskMem(buffer);
}
I was able to figure it out based off of existing code in my application (many thanks to Romoku for mentioning Marshal)
My completed code looks like:
int handle = 920663024; // integer pointer corresponding to memory location 0x36E033F0
IntPtr app_handle = helper.GetAppPtr(handle) // gets IntPtr based off of handle
object obj = Marshal.GetObjectForIUnknown(app_handle);
MyAppClass newApp = obj as MyAppClass;
Works like a charm!

Categories