Matlab crashes when running MEX Files with large array dimensions

9 views (last 30 days)
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!

Accepted Answer

James Tursa
James Tursa on 3 Jul 2017
Edited: James Tursa on 3 Jul 2017
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?

More Answers (1)

YosukyD
YosukyD on 3 Jul 2017
Edited: YosukyD on 4 Jul 2017
Thank you very much, James! I have fixed some things in the code and now it's working!
1.- I cannot believe how I totally forgot about prototyping the functions. I ran one of the example codes included with Matlab (ArrayProduct) and it doesn´t have any prototype functions, that's why I totally jumped this part.
2.- Yes, I was doing some changes in my code and by the time I posted this, I forgot to change it back that's why there is an incompatible type of data (Int *inMatrix to double *inMatrix). First, when I sent the example matrix (A), I was using this:
double *inMatrix;
inMatrix =mxGetPr(prhs[0]);
and my test function was:
void test (double *inMatrix, double *outMatrix, int f, int c, double a) end
Then, when I was trying to send an uint8 image, I changed it to:
int *inMatrix;
inMatrix=(int *)mxGetData(prhs[0]);
void test (int *inMatrix, double *outMatrix, int f, int c, double a)
But I forgot to change it back when I posted my code here.
3.- The image data I am passing to the function is uint8, that's why I made the mistake explained before. I was trying to use:
inMatrix = (uint8 *) mxGetData(prhs[0]);
But I get the message error of an invalid type name. At the end, I left it as a double and I just have to ensure to convert my uint8 image to double before calling the mex function.
4.- I know it is a bit strange, but I was just trying to be sure that the function will return the first dimension of the image I send to the Mex function, just to understand how it works. Of course, I can directly convert one by one element from inMatrix to outMatrix, but I am assuming that in the future, I may need to perform some other operations with the image before I return the final results, so I will be in need of use temporary arrays.
I appreciate your help, I put the prototype of the function and so far I haven´t had any more crashes :D

Categories

Find more on Read, Write, and Modify Image in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!