2

I have a C++ class which has a header(matrixheader.h) such that :

#pragma once

class M
{
    public:
        M(int m,int n);
        void MSet(int m,int n,double d);
        double MGet(int m,int n);
        ~M();
    private:
        double** mat;
};

Class is defined as follows in (matrixbody.cpp):It is built in Win32 Platform.

#pragma once
#include "matrixhead.h"

M::M(int m,int n)
{
  mat = new double*[m];
  for (int i = 0; i < m; i++)
  {
    mat[i] = new double[n];
  }
}

void M::MSet(int m,int n,double d)
{
    mat[m][n] = d;
}

double M::MGet(int m,int n)
{
    double d = mat[m][n];
    return d;
}

M::~M()
{
    delete[] mat;
}

I have made a wrapper for the Class like so(matrixwrapper.cpp):The wrapper is also built in Win32 platform.

#include "matrixhead.h"
#include "matrixbody.cpp"

extern "C" __declspec(dllexport) void* Make(int m,int n)
{
    M o(m,n);
    return &o;
}

extern "C" __declspec(dllexport) void setData(void* mp,int m,int n,double d)
{
    M* ap = (M*)mp;
    M a = *ap;
    a.MSet(m,n,d);
}

extern "C" __declspec(dllexport) double getData(void* mp,int m,int n)
{
    M* bp = (M*)mp;
    M b = *bp;
    double d = b.MGet(m,n);
    return d;
}

I import the class to C# and try to call the C++ dl methods from C#:

using System;
using System.Runtime.InteropServices;


namespace wrappertest
{
 class Program
   {
    [DllImport("matrixwrapper.dll")]
    unsafe public static extern void* Make(int m,int n);

    [DllImport("matrixwrapper.dll")]
    unsafe public static extern void setData(void* mp,int m, int n,double d);

    [DllImport("matrixwrapper.dll")]
    unsafe public static extern double getData(void* mp,int m, int n);

    static unsafe void Main(string[] args)
    {
        void* p = Make(10, 10);
        setData(p,10,1,10);
        Console.WriteLine(getData(p,10,1));
    }
  }
}

But when i try to run the C++ dll methods from C# i get the following error

1//Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.

2//An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.

Questions:

1//What is wrong in the above code ?

2//Considering that my final objective is to make a 2d dynamic array in C++ and read/write data in the array such as the one double**mat in the matrixheader.h file above from C#?is there any other way to implement it ?

  • Do you realize that `Make` returns a pointer to the stack? This is *very* bad... – Lucas Trzesniewski Jan 15 '15 at 12:51
  • So how do we fix this? Can you point me towrads an article which explains this error further ? – Aditya Patil Jan 15 '15 at 12:56
  • You could also make a C++/CLI wrapper instead, and have a more direct and clean usage in C#. – crashmstr Jan 15 '15 at 12:59
  • btw your matrix class leaks memory, please just use `std::vector` instead for dynamic arrays. Or at least make sure you delete all the child arrays as well before deleting the parent. The best choice is just to create the array in C# there is no need for C++ here. – Mgetz Jan 15 '15 at 12:59
  • No need for unsafe here. Element by element access will be slow. – David Heffernan Jan 15 '15 at 13:03
  • @Mgetz : i need to create large 2d arrays with 10,000*10,000 elements which for one is not supported in C# arrays and even if i implement via some other collection class manipulating them is very very slow in C# as compared to C++ – Aditya Patil Jan 15 '15 at 13:06
  • @AdityaPatil if you allocate as one m*n C# array it's a) not as slow b) more likely to work c) probably should still be built x64 – Mgetz Jan 15 '15 at 13:08
  • 1
    @Aditya In C#, `var test = new int[10000 * 10000];` works just fine. – Lucas Trzesniewski Jan 15 '15 at 13:08
  • @AdityaPatil - If you're creating 10000 x 10000 arrays, your matrix creation is horrible as it makes 10,001 calls to `new[]`. All you need are 2 calls to `new[]` and 2 calls to `delete[]`. Please see this answer here: http://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048 – PaulMcKenzie Jan 15 '15 at 13:13
  • @ lucas i tried it out manipulating such as operations for transposing takes around 29secs sometimes, after using Parallel.For in C# and other optimizations down to 1.2 to 3 secs.Can we make it faster if we lets say not allocate data for the array in C# but on the heap in C++ and process it and manipulate it in C++ dll itself and get back the result after a long process of manipulation back to C#? – Aditya Patil Jan 15 '15 at 13:15
  • @Mgetz: in the matrixheader.h file i mention a ~M(); which is defined as ~M(){delete[] mat;} will this not be called automatically when object M is deleted ? i thought this would not create a memory leak. – Aditya Patil Jan 15 '15 at 13:17
  • @AdityaPatil - For each call to `new[]`, you need a call to `delete[]`. Did you read my comment? You called `new[]` 10,001 times. So your destructor is not correct -- it leaks memory. Also, to add to my previous comment, your allocation is not only slow, it is *highly* flawed -- please see this: http://stackoverflow.com/questions/27425126/dynamic-allocation-of-two-dimensional-array-c/27425293#27425293 – PaulMcKenzie Jan 15 '15 at 13:19
  • @PaulMcKenzie: Yes im looking through the link you mentioned in the above comment. – Aditya Patil Jan 15 '15 at 13:21
  • @AdityaPatil - I updated my comment to you. Consider what happens if one of those calls to `new[]` faiils due to an exception being thrown. What do you do then? It is much easier to either use `std::vector` or seriously reduce the number of calls to `new[]` to a minimum amount in case of `new[]` failure. – PaulMcKenzie Jan 15 '15 at 13:23
  • @PaulMcKenzie i understand.I agree using std::vector is better. – Aditya Patil Jan 15 '15 at 13:32

1 Answers1

1

Let's get the easy thing first:

An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.

This simply means you have a platform mismatch. You're either trying to load an x86 C++ dll in an x64 .NET runtime, or the reverse.

The following error is the real problem:

Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.

That's to be expected, because your Make function creates an object on the stack, then returns a pointer to it. By the time you read back this object, the contents on the stack has changed (the stack is being reused), and the mat pointer points somewhere else, most probably into unallocated memory.

Please see this answer where I go into deeper detail about this issue (it's C# but it's the same issue).

You have to allocate some dynamic memory to solve your problem. You may try:

extern "C" __declspec(dllexport) void* Make(int m,int n)
{
    M* o = new M(m,n);
    return o;
}

And of course, you'll have to create one more method to perform the matching delete if you don't want to leak memory.

Also, like Mgetz points out in the comments, you have a memory leak in the M class itself. The delete[] mat; call in the destructor won't free every allocated chunk of memory. You're calling new in the constructor m + 1 times, this means you have to call delete[] m + 1 times also in the destructor, once for each new. You probably should keep m and n as fields in your class (at least m is mandatory to know how many calls to delete[] you have to do).

A much better solution would be to use a single array instead of jagged arrays. You calculate the index i, j in that array as i * m + j. You may also use a std::vector or just do it in C# altogether:

public class M
{
    private double[] _items;
    private int _m;
    private int _n;

    public M(int m, int n)
    {
        _items = new double[m * n];
        _m = m;
        _n = n;
    }

    public this[int i, int j]
    {
        // Here, you should perform a bounds check on i and j against _m and _n
        get { return _items[i * _m + j]; }
        set { _items[i * _m + j] = value; }
    }
}
Community
  • 1
  • 1
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • 1
    he doesn't even need the C++, he can just create the whole thing in C# and it will probably be faster than the cost of the interop. If for some reason he does need C++ he should probably just use an m*n length `std::vector` and then index in. Allocating each line of the matrix separately is actually much more expensive and makes indexing into it slower. – Mgetz Jan 15 '15 at 13:06
  • @Mgetz absolutely, I was going to suggest the same thing but you beat me to it ;) – Lucas Trzesniewski Jan 15 '15 at 13:10
  • @Mgetz and Lucas thanks guys i will take up your suggestions and implement them.I knew i could do this the using vector class as Mgetz suggested and flattening the array but i wanted to figure out which method was faster thus the above implementation – Aditya Patil Jan 15 '15 at 13:26