MATLAB Answers

0

Crash with a mex file, using mxMalloc, mxCalloc and complex vectors

Asked by Carine on 8 Oct 2012
Hi,
I am trying to write a mex file but I can't find out what does not work in it. I have "emptied" it and wrote a test one but it still doesn't work. Matlab is killed each time I try to run it. To run it, I take a random signal: x = randn(1,16); and then type y = test(x) Could you give me a hint? Here is the code:
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int N, *partitions;
int taille, i;
double *partdouble;
double *sigi, *sigr, *gftr, *gfti, *win, *signal, *gft;
char *windowtype;
void *window;
/* create a pointer to the real data in the input matrix */
sigr = mxGetPr(prhs[0]);
signal = mxMalloc(2*N*sizeof(mxCOMPLEX));
/* get dimensions of the input matrix */
N = mxGetM(prhs[0]);
if (N == 1)
N = mxGetN(prhs[0]);
/* If not complex, set imaginary part to 0 */
if (!mxIsComplex(prhs[0]))
sigi = mxCalloc(N, sizeof(mxREAL));
else
sigi = mxGetPi(prhs[0]);
/* In C, real and complex values are interleaved whereas in Matlab
* there are split. Therefore create a complex signal of size 2N with 0
* interleaved as the original signal is real */
for (i = 0; i<N; i++) {
signal[i] = sigr[i];
signal[2*i+1] = sigi[i];
}
/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1,N, mxCOMPLEX);
/* get a pointer to the real data in the output matrix */
gftr = mxGetPr(plhs[0]);
gfti = mxGetPi(plhs[0]);
gft = mxCalloc(N,sizeof(mxCOMPLEX));
for (i=0; i<2*N; i++){
gft[i] = signal[i];
}
for (i = 0; i<N; i++) {
mexPrintf("gft[%d] = %lf\t gft[%d] = %lf\n", 2*i, gft[2*i], 2*i+1, gft[2*i+1]);
gftr[i] = gft[2*i];
gfti[i] = gft[2*i+1];
}
mexPrintf("The end\n");
}
One of the side questions is that as signal should be an N-complex vector, should I declare it as signal = mxMalloc(2*N*sizeof(mxCOMPLEX)); or signal = mxMalloc(N*sizeof(mxCOMPLEX));? Cheers, Carine

  0 Comments

Sign in to comment.

3 Answers

Answer by James Tursa
on 8 Oct 2012
Edited by James Tursa
on 8 Oct 2012
 Accepted Answer

This loop is wrong for the real part sigr:
for (i = 0; i<N; i++) {
signal[i] = sigr[i]; // should be signal[2*i] = etc.
signal[2*i+1] = sigi[i];
}
You ignored my previous advice about the size of gft. Since it is the interleaved complex data, it needs to be allocated to 2*N, not N (this is what is causing the seg fault):
gft = mxCalloc(N,sizeof(*gft)); // should be 2*N, not N
Also, as an efficiency suggestion, I would not allocate a 0 block for sigi up front. That is wasted effort and memory and slows down the code. I know this makes the downstream code simpler, but I would still opt for a bit of extra code downstream to handle it vice extra memory & copying. E.g., something like this:
if (mxIsComplex(prhs[0])) {
sigi = mxGetPi(prhs[0]);
for (i = 0; i<N; i++) {
signal[2*i ] = sigr[i];
signal[2*i+1] = sigi[i];
}
} else {
for (i = 0; i<N; i++) {
signal[2*i ] = sigr[i];
signal[2*i+1] = 0.0; // might not need this, see below
}
}
This also avoids the need to conditionally free sigi downstream (which you did not do btw). All of the mxCreateEtc API functions 0 out the data areas, which is why you don't need to explicitly do this in your code. Additionally, it appears that mxMalloc also 0's out the memory it returns from all tests I have done. If you don't want to rely on that then use mxCalloc or explicitly 0 out the imaginary elements in your code.

  1 Comment

It finally works, many thanks!!!

Sign in to comment.


Answer by James Tursa
on 8 Oct 2012

You use N before you set its value:
signal = mxMalloc(2*N*sizeof(mxCOMPLEX)); // Use it here
/* get dimensions of the input matrix */
N = mxGetM(prhs[0]); // Set its value here
Also, you should not be using sizeof(mxCOMPLEX) or sizeof(mxREAL) for memory allocation. mxCOMPLEX and mxREAL are enumeration integer values used as flags in API calls ... they are not the data type itself. In your memory allocation:
signal = mxMalloc(2*N*sizeof(*signal));
:
sigi = mxCalloc(N, sizeof(*sigi));
:
gft = mxCalloc(2*N,sizeof(*gft));
In addition, for the complex ones that you had you may need to use 2*N instead of N as noted.

  0 Comments

Sign in to comment.


Answer by Carine on 8 Oct 2012

Thanks for the answer James. Sorry for the signal declaration before N, it was correct but modifying I made a mistake. Anyway, I followed your advice but it does still crash with memory allocation errors. In between lots of things on my xterm, I've got this when Matlab crashes:
*** glibc detected *** /usr/local/MATLAB/R2012a/bin/glnxa64/MATLAB: free(): corrupted unsorted chunks: 0x00007f03f7702a10 ***
glibc detected *** /usr/local/MATLAB/R2012a/bin/glnxa64/MATLAB: malloc(): memory corruption: 0x00007f03f76f2af0 ***
I have tried to free the memory to see if it would improve the code. Here is the modified script:
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int N, *partitions;
int taille, i;
double *partdouble;
double *sigi, *sigr, *gftr, *gfti, *win, *signal, *gft;
char *windowtype;
void *window;
/* create a pointer to the real data in the input matrix */
sigr = mxGetPr(prhs[0]);
/* get dimensions of the input matrix */
N = mxGetM(prhs[0]);
if (N == 1)
N = mxGetN(prhs[0]);
/* If not complex, set imaginary part to 0 */
if (!mxIsComplex(prhs[0]))
sigi = mxCalloc(N, sizeof(*sigi));
else
sigi = mxGetPi(prhs[0]);
signal = mxMalloc(2*N*sizeof(*signal));
/* In C, real and complex values are interleaved whereas in Matlab
* there are split. Therefore create a complex signal of size 2N with 0
* interleaved as the original signal is real */
for (i = 0; i<N; i++) {
signal[i] = sigr[i];
signal[2*i+1] = sigi[i];
}
/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1,N, mxCOMPLEX);
/* get a pointer to the real data in the output matrix */
gftr = mxGetPr(plhs[0]);
gfti = mxGetPi(plhs[0]);
gft = mxCalloc(N,sizeof(*gft));
for (i=0; i<2*N; i++){
gft[i] = signal[i];
}
for (i = 0; i<N; i++) {
mexPrintf("gft[%d] = %lf\t gft[%d] = %lf\n", 2*i, gft[2*i], 2*i+1, gft[2*i+1]);
gftr[i] = gft[2*i];
gfti[i] = gft[2*i+1];
}
mexPrintf("The end\n");
mxFree(signal);
mxFree(gft);
}
Cheers.

  0 Comments

Sign in to comment.