Note that there are some explanatory texts on larger screens.

plurals
  1. POSafe and Correct Struct Marshalling
    primarykey
    data
    text
    <h2>Unmanaged and Managed Memory Regions</h2> <p>I am attempting to execute unmanaged code from a C-library. One of the methods takes a <code>void*</code> as a parameter but under the hood it's cast to a struct of type <code>nc_vlen_t</code></p> <h3>C struct for nc_vlen_t</h3> <pre><code>/** This is the type of arrays of vlens. */ typedef struct { size_t len; /**&lt; Length of VL data (in base type units) */ void *p; /**&lt; Pointer to VL data */ } nc_vlen_t; </code></pre> <p>Executing the method is correct and it works, I am concerned more about the pinning and safe handling of managed and unmanaged memory regions. I want to be as certain as possible that I am not going to cause memory leaks or a SEGFAULT. I wrote a struct that will be marshalled to and from the <code>nc_vlen_t</code> when I execute the C-library method calls.</p> <h3>C# struct</h3> <pre><code>[StructLayout(LayoutKind.Sequential)] public struct VlenStruct { public Int32 len; public IntPtr p; // Data } </code></pre> <p>The struct consists of a <code>size_t</code> that indicates the array length and a <code>void *</code> to the data. Inside the library it has attributes that allow it to cast the (void*) to the appropriate numeric types and I've had great success with that so far. </p> <p>What I want to understand is the best way to handle the memory regions. After reading some articles and other SO questions this is my best <em>guess</em> for how to handle it. I have a class that acts as an arbiter for creating and managing the structs and their memory. I rely on a destructor to free the handle which will unpin the array so that the GC can do it's job. </p> <h3>C# Vlen Helper</h3> <pre><code>public class Vlen { private GCHandle handle; private VlenStruct vlen_t; public Vlen() { isNull = true; } public Vlen(Array t) { isNull = false; handle = GCHandle.Alloc(t, GCHandleType.Pinned); // Pin the array vlen_t.len = t.Length; vlen_t.p = Marshal.UnsafeAddrOfPinnedArrayElement(t, 0); // Get the pointer for &amp;t[0] } ~Vlen() { if(!isNull) { handle.Free(); // Unpin the array } } public VlenStruct ToStruct() { VlenStruct retval = new VlenStruct(); retval.len = vlen_t.len; retval.p = vlen_t.p; return retval; } private bool isNull; } </code></pre> <h3>C Method Declaration</h3> <pre><code> //int cmethod(const int* typep, void *data) // cmethod copies the array contents of the vlen struct to a file // returns 0 after successful write // returns -1 on fail [DllImport("somelib.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true, CallingConvention=CallingConvention.Cdecl)] public static extern Int32 cmethod(ref Int32 typep, ref VlenStruct data); </code></pre> <p>If I use this class to create the struct is there a possibility that the GC will clean the array before the C-library is called in this situation:</p> <h3>C# Use-case</h3> <pre><code>{ double[] buffer vlenBuffer = new double[] { 0, 12, 4}; Vlen data = new Vlen(vlenBuffer); // The instance now pins buffer VlenStruct s = data.ToStruct() Int32 type = VLEN_TYPE; cmethod(ref type, ref s); } </code></pre> <p>Is it possible for the <code>data</code> instance to be cleaned and thereby unpin <code>buffer</code> which could cause unpredictable behavior when executing the external library method?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload