165 views (last 30 days)

Show older comments

I try to build a mex interface for a C function r8mat_expm1() that calculates matrix exponential,

double *r8mat_expm1 ( int n, double a[] );

Where n is the dimension and a is the matrix.

My mex function my_expm.c is as follows,

void mexFunction(int nlhs,mxArray *plhs[], int nrhs, const mxArray *prhs[])

{

double *tmpResult;

double *inputMat;

int numRows;

numRows = mxGetM(prhs[0]);

inputMat = mxGetPr(prhs[0]);

tmpResult = mxMalloc(numRows*numRows*sizeof(*tmpResult));

tmpResult = r8mat_expm1(numRows, inputMat); // calculate matrix exponential

plhs[0] = mxCreateDoubleMatrix(numRows, numRows, mxREAL);

mxSetDoubles(plhs[0], tmpResult);

mxFree(tmpResult);

}

Which parse the input and call the computational routine r8mat_expm1().

After building on linux, I use

c=my_expm(2,[1,0;0,2]') % this is problematic, thanks Bruno Luong for pointing out

to run the compiled function. However, it just crashes matlab, and "Segmentation fault (core dumped) matlab" appears on linux terminal.

I suspect this is related to mxMalloc() and mxSetDoubles(). When I did not use these two functions, matlab will not crash. I chose to use mxSetDoubles() to fix an error, as suggested in this post.

I also tried another suggestion in that post, i.e. change r8mat_expm1() from

double *r8mat_expm1 ( int n, double a[] );

to

void r8mat_expm1 ( int n, double a[], doule output[] );

to avoid return all zeros error, but it still return all zeros.

So what is the problem behind this and how can I fix this crash error or get the right ouput instead of all zeros?

James Tursa
on 26 Dec 2020

Edited: James Tursa
on 26 Dec 2020

You have memory leaks in your current code. E.g.,

tmpResult = mxMalloc(numRows*numRows*sizeof(*tmpResult)); // this memory gets leaked by the very next line

tmpResult = r8mat_expm1(numRows, inputMat); // leaks memory from the mxMalloc( ) call

plhs[0] = mxCreateDoubleMatrix(numRows, numRows, mxREAL); // this memory gets leaked by the very next line

mxSetDoubles(plhs[0], tmpResult); // leaks memory from the mxCreateDoubleMatrix( ) call

This leaked memory is bad but does not cause the crash.

It appears you attach native C/C++ allocated memory to an mxArray, and this will cause a crash. You can't mix native C/C++ allocated memory in an mxArray. All memory in an mxArray must come from MATLAB API memory allocation functions.

You really need to post some details about the r8mat_expm1( ) function for us to be sure about what the real problem is. But from your description it sounds like it allocates the memory for the result using native C/C++ routines (e.g., malloc or calloc) and then returns the pointer to that, which you then attach to an mxArray ... resulting in a crash. If this is true, then you will either need to change the function to use MATLAB API allocation functions, or copy the results. To copy the results you would do something like this:

#include <string.h> // for memcpy( )

#include <stdlib.h> // for free( )

double *tmpResult;

double *inputMat;

double *pr;

int numRows;

numRows = mxGetM(prhs[0]);

inputMat = mxGetDoubles(prhs[0]);

tmpResult = r8mat_expm1(numRows, inputMat); // calculate matrix exponential

plhs[0] = mxCreateDoubleMatrix(numRows, numRows, mxREAL);

pr = mxGetDoubles(plhs[0]);

memcpy(pr,tmpResult,numRows*numRows*sizeof(double));

free(tmpResult); // use free( ) for native C/C++ allocated memory

To avoid the data copy and use MATLAB API allocation functions, you would need to alter the source code of r8mat_expm1( ) and pass in the pointer instead of allocating memory inside the function. Then your mexFunction( ) code would look like this instead of the above:

double *inputMat;

double *pr;

int numRows;

numRows = mxGetM(prhs[0]);

inputMat = mxGetDoubles(prhs[0]);

plhs[0] = mxCreateDoubleMatrix(numRows, numRows, mxREAL);

pr = mxGetDoubles(plhs[0]);

r8mat_expm1(numRows, inputMat, pr); // calculate matrix exponential

And the signature for the r8mat_expm1( ) function would change to this:

void r8mat_expm1(int, double *, double *);

where the 3rd input argument is used inside r8mat_expm1( ) for the output, and no memory allocation is done inside this function.

Another way to do this is to change the malloc( ) and calloc( ) inside r8mat_expm1( ) to be mxMalloc( ) and mxCalloc( ) instead, and then attach that result to the mxArray. If you want I can post that code, but frankly it is more complicated than what I have posted above so I would see no practical reason to code it this way.

Bruno Luong
on 26 Dec 2020

You must not call

mxFree(tmpResult);

Since the data is attached to the output.

Bruno Luong
on 26 Dec 2020

You seem to call

mxGetM(prhs[0])

To get dimensions of the first parameter of calling

c=my_expm(2,[1,0;0,2]')

which is 2 and not the 2x2 matrix.

Who knows what else. The mex code seem to have quality issue, which is not tolerable and resulting crash.

Bruno Luong
on 27 Dec 2020

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!