Problem in using mxSetPr

3 views (last 30 days)
AP
AP on 21 Nov 2014
Commented: James Tursa on 18 Apr 2017
I am writing a function within in a mex file which calls a MATLAB function. Unfortunately, when it comes to mxSetPr, MATLAB crashes and does not proceed further. Could someone kindly tell me how I can fix this?
void myfun( double *Ain , double *Aout,
int AnRows , int AnCols,
double *kernel, int kernelnRows, int kernelnCols )
{
mxArray *rhs[3], *lhs[1];
rhs[0] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[1] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[2] = mxCreateString ( "same" );
mxSetPr( rhs[0], Ain );
mxSetM ( rhs[0], AnRows );
mxSetN ( rhs[0], AnCols );
mxSetPr( rhs[1], kernel );
mxSetM ( rhs[1], kernelnRows );
mxSetN ( rhs[1], kernelnCols );
mexCallMATLAB(1, lhs, 3, rhs, "conv2");
Aout = mxGetPr( lhs[0] );
}

Accepted Answer

Geoff Hayes
Geoff Hayes on 23 Nov 2014
AP - the documentation for mxSetPr indicates that for the second input parameter to this function,
The array must be in dynamic memory; call mxCalloc to allocate this memory. Do not use the ANSI® C calloc function, which can cause memory alignment issues leading to program termination. If pr points to static memory, memory leaks and other memory errors can result.
Did you use mxCalloc to allocate memory to Ain and kernel? That being said, I did try the following test function
void test()
{
mxArray* myMxArray = 0;
double* myDblArray = 0;
myMxArray = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
myDblArray = mxCalloc(4,sizeof(double));
if (myMxArray!=NULL && myDblArray!=NULL)
{
mxSetPr(myMxArray,myDblArray);
mxSetM(myMxArray,2);
mxSetN(myMxArray,2);
mxFree(myDblArray);
mxDestroyArray(myMxArray);
}
}
and the above crashed at the mxSetPr line. So I am a little puzzled by the above. James Tursa would most likely know what is wrong with the above code.
-------
The only time I've seen mxSetPr being used in for output (the lhs) of the mexFunction, so if I had to do something similar to what you are doing, I would have tried the following
void myfun2(double *Ain , int AnRows , int AnCols,
double *kernel, int kernelnRows, int kernelnCols,
mxArray **lhs)
{
mxArray *rhs[3];
double *ptr;
// create the mxArrays
rhs[0] = mxCreateNumericMatrix( AnRows, AnCols, mxDOUBLE_CLASS, mxREAL );
rhs[1] = mxCreateNumericMatrix( kernelnRows, kernelnCols, mxDOUBLE_CLASS, mxREAL );
rhs[2] = mxCreateString ( "same" );
// copy the Ain and kernel data
ptr = mxGetPr(rhs[0]);
memcpy(ptr,Ain,sizeof(double)*AnRows*AnCols);
ptr = mxGetPr(rhs[1]);
memcpy(ptr,kernel,sizeof(double)*kernelnRows*kernelnCols);
mexCallMATLAB(1, lhs, 3, rhs, "conv2");
// destroy the mxArrays
mxDestroyArray(rhs[0]);
mxDestroyArray(rhs[1]);
mxDestroyArray(rhs[2]);
}
Note in the above how memcpy is used to copy the data from the Ain and Kernel arrays to the destination mxArrays. Note also that for every create of an mxArray, we must destroy or free memory allocated to that array.
For the case of the left-hand side result of the convolution, we pass an mxArray into this function as
mxArray **lhs
As (presumably) memory will be dynamically allocated to it within the conv2 function, the caller of myfun2 does not need to allocate memory to this parameter, but the caller will be responsible for freeing the memory. For example,
// do some work to create the Ain and Kernel matrices
// declare the output matrix from the 2D convolution
mxArray *convMtx = 0;
// call the function to do the 2D convolution
myfun2(Ain, AnRows, AnCols,kernel,kernelnRows,kernelnCols,&convMtx);
if (convMtx!=NULL)
{
// do some stuff with convMtx
// destroy mxArray
mxDestroyArray(convMtx);
}
See how we pass the convMtx into the function as &convMtx.
  3 Comments
Geoff Hayes
Geoff Hayes on 24 Nov 2014
Without knowing the sizes of your matrices or how often you expect to call this function, I can't comment on your assertion that copying will significantly reduce the efficiency and speed of your code.
James Tursa
James Tursa on 18 Apr 2017
Commenting on an old post ...
In the first code section above:
void test()
{
mxArray* myMxArray = 0;
double* myDblArray = 0;
myMxArray = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
myDblArray = mxCalloc(4,sizeof(double));
if (myMxArray!=NULL && myDblArray!=NULL)
{
mxSetPr(myMxArray,myDblArray); <-- (1)
mxSetM(myMxArray,2);
mxSetN(myMxArray,2);
mxFree(myDblArray); <-- (2)
mxDestroyArray(myMxArray); <-- (3)
}
}
"... and the above crashed at the mxSetPr line. So I am a little puzzled by the above. James Tursa would most likely know what is wrong with the above code."
Line (1) attaches the pointer myDblArray to the mxArray myMxArray (and at the same time removes myDblArray from the garbage collection list). Note that this attaches the actual pointer value, not some type of copy.
Line (2) frees the memory behind myDblArray, which now means that myMxArray has an invalid pointer as its real data pointer.
Line (3) attempts to free the memory behind myDblArray again. But this pointer is invalid because of (2), hence the crash.
The fix is to remove line (2).

Sign in to comment.

More Answers (0)

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!