MATLAB: Matlab crashes when running MEX Files with large array dimensions

c mex filemex

Hello everyone! I am starting to use C Mex files. So far, I'm running a test on how to work with multidimensional arrays. From Matlab, I'm sending an image (3 channels, so it will be mxnx3). The MEX File receives the images and calls another function (test). The only thing that my test function does, is to receive the image (mxnx3) and takes the first dimension (mxnx1) and multiply it by a scalar (a).
The problem is that my function only works when I send small arrays (4x3x3), but when I try to send an image, it crashes at the end (looks like it crashes when Max File finishes and return to Matlab).
My code is:
#include "mex.h"
#include "matrix.h"
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double *outMatrix;
mwSize f,c,dims;
double a;
int *inMatrix;
double *pr,*pi;
inMatrix = (int *) mxGetData(prhs[0]);
a = mxGetScalar(prhs[1]);
const mwSize *dima = mxGetDimensions(prhs[0]);
f=dima[0]; //Number of rows
c=dima[1]; //Number of cols
mwSize numel = mxGetNumberOfElements(prhs[0]);
mexPrintf("a= %f\n",a);
mexPrintf("rows= %d\n",f);
mexPrintf("cols= %d\n",c);
plhs[0] = mxCreateDoubleMatrix(f,c,mxREAL);
outMatrix = mxGetPr(plhs[0]);
test(inMatrix,outMatrix,f,c,a);
}
void test(double *inMatrix, double *outMatrix, int f, int c, double a)
{
double image[f][c],aux;
int i,j,k;
for (j=0; j<c; j++)
for (i=0; i<f; i++)
image[i][j]=inMatrix[f*j+i]*a;
//Converting back the image to array
for (j=0; j<c; j++)
for (i=0; i<f; i++)
outMatrix[f*j+i]=image[i][j];
}
From Matlab, I call the function like this:
B=[1 2 5 3; 7 8 9 6;1 4 5 6]; A(:,:,1)=B; A(:,:,2)=B; A(:,:,3)=B; C=mextest1(A,5);
And it works, because the returned matrix is:
C =
5 10 25 15
35 40 45 30
5 20 25 30
I need your help to understand what can be my error in the code. Thank you very much!

Best Answer

There are several issues:
1) You don't prototype your test function.
The compiler encounters this line:
test(inMatrix,outMatrix,f,c,a);
before it encounters this line:
void test(double *inMatrix, double *outMatrix, int f, int c, double a)
Because of that, at the point the first line is compiled, the compiler has no clue what the real signature of the test function is, so you will get NO automatic argument type promotion help from the compiler. At the point of the test function call, the compiler thinks the signature for the test function is this:
int test(int *, double *, mwSize, mwSize, double)
when the actual signature is really this:
void test(double *, double *, int, int, double)
You are setting yourself up for major headaches in debugging your code if you do not use prototypes for your functions. I know C doesn't require them (although C++ does), but really you should get in the habit of always using prototypes!
2) You can't change underlying data types just by using a different type of pointer.
E.g., take these lines:
int *inMatrix;
:
inMatrix = (int *) mxGetData(prhs[0]);
:
test(inMatrix,outMatrix,f,c,a);
:
void test(double *inMatrix, double *outMatrix, int f, int c, double a)
The data type of prhs[0] is going to be whatever it is, and you can't change it by using a different type of data pointer. In your specific example case, the incoming data type is double. You can't use a (pointer_to_int) to point to the data and expect to be able to read the underlying data as int's. The underlying data is still double, not int. So using a (pointer_to_int) in this case makes absolutely no sense. In fact, had you used a function prototype for test like you should have, the compiler would have helped you out here and complained that you were mixing two different pointer types. That would have alerted you to the programming error. But since you did not use a prototype, the compiler had no clue about your programming error and you got no help. The only reason your code "worked" on your example is because the test function treated the underlying data as double, which it was. (The (pointer_to_int) got passed to the test function, which silently used it as a (pointer_to_double) type instead).
Bottom line here is you need to ensure the pointer type you are using actually matches the underlying data type that is present. If you need the data type to be different for downstream processing in your code, you will need to manually convert it inside your C code.
3) The image data you are passing in for your larger test is probably not double type ... it is probably some other type like uint8.
Since your test function blindly assumes that the underlying data is double, if it is anything shorter (like uint8) you run the risk of running off the end of the array and accessing invalid memory, resulting in a seg fault. The fix here is really the same as (2) above ... you need to ensure that the pointers you are using actually match the underlying data type that is present. That means using functions like mxIsDouble or mxIsUint8 etc up front in your code to make sure that the incoming data type is as expected before trying to access it.
4) The coding method used in your test function is a bit strange.
E.g., consider this line:
double image[f][c],aux;
The image variable is a local variable, which means its memory will be allocated off of the stack. Usually it is not a good practice to dynamically allocate arrays off of the stack like this because you may never know in advance how large the variable will be. If f and c are too large, you will blow your stack memory and seg fault. If you really need to allocate arrays in your function, it is generally better practice to use the heap (i.e. the allocation functions mxMalloc, mxCalloc) rather than the stack like you are doing.
Also, what is the point of allocating this array anyway? Why are you stuffing the entire converted result into a temporary stack array? Why not just one-by-one do the element conversion and stuff them into the result directly?