MATLAB Answers

With mxMalloc() and mxSetDoubles(), mex function crash matlab

조회 수: 155(최근 30일)
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?

  댓글 수: 3

Steven Lord
Steven Lord 29 Dec 2020
Is your goal to write a function to compute the matrix exponential or is your goal to compute the matrix exponential? If the latter, consider simply calling the expm function in MATLAB. [Even if you want to or are required to write the function yourself (for a homework assignment, perhaps) you can check your results against expm.]
Bruno Luong
Bruno Luong 29 Dec 2020
He did compare his code againts expm.
Xingwang Yong
Xingwang Yong 30 Dec 2020
The latter, but I want to do this in C language. I compiled it to see if it works by comparing its output to matlab built-in expm(). But later I found there is already a test case to demonstrate its effectiveness. So no need to compile it for comparison...

댓글을 달려면 로그인하십시오.

채택된 답변

James Tursa
James Tursa 26 Dec 2020
편집: James Tursa 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.

  댓글 수: 18

표시 이전 댓글 수: 15
Xingwang Yong
Xingwang Yong 30 Dec 2020
Yes, you are right.
I used
plhs[0] = mxCreateDoubleMatrix(numRows, numRows, mxREAL);
mxDestroyArray(plhs[0]);
This just deletes everything and I can not get the desired output.
Bruno Luong
Bruno Luong 30 Dec 2020
Wait, why do you want to destroy/free with plhr[0] in your mex function? This supposes to be the result returned by the mex function, so you must leave it alone. What are trying to do?
I'm just afraid that you missundestand completely the dataflow of mex file.
Xingwang Yong
Xingwang Yong 30 Dec 2020
No, no, no, I just try it. I won't use it.

댓글을 달려면 로그인하십시오.

추가 답변(2개)

Bruno Luong
Bruno Luong 26 Dec 2020
You must not call
mxFree(tmpResult);
Since the data is attached to the output.

  댓글 수: 4

표시 이전 댓글 수: 1
Bruno Luong
Bruno Luong 26 Dec 2020
Then you have other problem in the code r8mat_expm1.
Xingwang Yong
Xingwang Yong 26 Dec 2020
Yes, r8mat_expm1() called some other C sub-routines, which contains alloc() and free().
Do you have any idea how can I copy the output of 8mat_expm1(), which is double * , to the output of mex function?
Xingwang Yong
Xingwang Yong 26 Dec 2020
Yes, r8mat_expm1() called some other C sub-routines, which contains alloc() and free().
Do you have any idea how can I copy the output of 8mat_expm1(), which is double * , to the output of mex function?

댓글을 달려면 로그인하십시오.


Bruno Luong
Bruno Luong 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.

  댓글 수: 7

표시 이전 댓글 수: 4
Bruno Luong
Bruno Luong 27 Dec 2020
I think James has answered many question you raised already.
First, r8mat_expm1 use MALLOC to allocate resulting array "e", see the code of
double *r8mat_identity_new ( int n )
...
a = ( double * ) malloc ( n * n * sizeof ( double ) );
...
return a;
Your claim "The function r8mat_expm1() does not use malloc() for the result" is just plain wrong.
You are not allowed to assign a data array of an mxArray allocated with generic C MALLOC. You have to use mxMalloc.
The safest modification is to do exactly what he advises
#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
Obviously you are not the owner of r8mat_expm1, If I was you I would avoid to change r8mat_expm1 in case the authors of those function updates the code in the futur.
"if I do not use mxMalloc() for tmpResutl, this would give right result to tmpResult in mex fucntion although the result returned to matlab is wrong."
The fact that you use mxMalloc before calling r8mat_expm1 is just make memory leaks (you allocate but then throw it away since the original pointer is lost after function returns). And beside it is still not allowed since r8mat_expm1 uses MALLOC.
Xingwang Yong
Xingwang Yong 27 Dec 2020
Thank you, Bruno. As you wrote this comment, I did my homework about pointers and digged up in the C source code and found the memory of final result is allocated by r8mat_identity_new(), same as you found.
"Your claim "The function r8mat_expm1() does not use malloc() for the result" is just plain wrong." Sorry for the mistake, at first I only searched the word 'malloc' inside r8mat_expm1() and did not go further into sub-routines. So I said in my previous comment "it did not call malloc() directly". I'll edit my comment under James's answer to avoid ambiguity.
"The fact that you use mxMalloc before calling mxGetDoubles", is this a typo error? I think mxGetDoubles should be replaced by r8mat_expm1 or mxSetDoubles. I did not use mxGetDoubles in my code.
Anyway, I've got your point about my wrong usage of pointers. Thank you.
Bruno Luong
Bruno Luong 27 Dec 2020
Sorry, you are right I make a typo. Shoul read "The fact that you use mxMalloc before calling r8mat_expm1 "

댓글을 달려면 로그인하십시오.

Community Treasure Hunt

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

Start Hunting!

Translated by