tags:

views:

439

answers:

3

I'm reading from a binary data file which is written by invoking the following lines in Matlab m-file:

disp(sprintf('template = %d', fwrite(fid, template_1d, 'uint8')));
AFAIK, uint8 is the same size as the types BYTE, unsigned char, and unsigned short. Hence I have written the following code in a file-reading method in a C++ class instantiated in the mexfunction called by Matlab:
template1D = (unsigned short*) malloc(Nimgs*sizeof(unsigned short));
printf("template1D = %d\n", fread(template1D, sizeof(unsigned short), Nimgs, dfile));

and the following is how I deallocated this member variable in the class destructor's helper function:

free((void*) template1D);

In the main mexfunction, when I did not instantiate the class object to persist in memory after mex-function completes by calling mexMakeMemoryPersistent() function, template1D gets cleared properly without segmentation error messages from Matlab. However, if I did instantiate the class to persist in memory as follows:

if (!dasani)
{
    dasani = new NeedleUSsim;
    mexMakeMemoryPersistent((void*) dasani);
    mexAtExit(ExitFcn);
}

with ExitFcn being:

void ExitFcn()
{
    delete dasani;
}

then when I'm at the line of free((void*) template1D);, Matlab gives me an error message about the segmentation fault. I have checked the memory sizes and they seem to be consistent. For the malloc/calloc/free functions, I'm using Matlab's mxMalloc/mxCalloc/mxFree functions when I'm executing the C++ project as a Matlab mex function.

Based on this description, what further suggestions would you have for me to solve this problem and ensure this doesn't happen in the future (or at least know how to deal with similar problems like this in the future)?

Thanks in advance.

----------------------------Additions------------------------------------------------------

The following block of code basically shows the jists of my mex file. A mex file is basically an executable that is run in Matlab and compiled from C/C++ code with some Matlab headers.

void ExitFcn()
{
    delete dasani;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    needle_info pin;

    // check number of i/o if they are correct
    if (nrhs != NUMIN)
    {
     mexErrMsgTxt("Invalid number of input arguments");
    }
    else if (nlhs != NUMOUT)
    {
     mexErrMsgTxt("Invalid number of output arguments");
    }

    // check if the input is noncomplex
    if (mxIsComplex(NEEDLE))
    {
     mexErrMsgTxt("Input must be a noncomplex scalar integer.");
    }

    // check if the dimensions of the needle information is valid
    int needlerows, needlecols;
    needlerows = mxGetM(NEEDLE);
    needlecols = mxGetN(NEEDLE);
if (needlerows < 1 || needlecols < 6)
    {
     mexErrMsgTxt("Needle information's dimensions are invalid");
    }

    float *needlePoint, *yPoint ;

    // retrieving current needle information
    // order of the variables are always as follows:
    // r, theta, l, rho, alpha, beta
    needlePoint = (float*) mxGetData(NEEDLE) ;
    pin.r = needlePoint[0];
    pin.theta = needlePoint[1];
    pin.l = needlePoint[2];
    pin.rho = needlePoint[3];
    pin.alpha = needlePoint[4];
    pin.beta = needlePoint[5];

    //// read the file inputs
    **//if (!dasani)
    //{
    // dasani = new NeedleUSsim;
    // mexMakeMemoryPersistent((void*) dasani);
    // mexAtExit(ExitFcn);
    //}
    dasani = new NeedleUSsim;
    delete dasani;**

    // sending an useless output for now (get rid of this if not conceptually needed
    plhs[0] = mxCreateNumericMatrix(1,1,mxSINGLE_CLASS,mxREAL) ;
    yPoint = (float*) mxGetData(plhs[0]) ;
    *yPoint = 1;
}

This code would run after build/compilation if the user invokes "mexfunction" anywhere from the command line or m-file script. The snippet enclosed by "**" (when I was trying to bold the snippet) is the problem that I'm looking at. From a second look at the snippet, I may be allocating the memory for dasani pointer in a different memory from the Matlab memory (as there is the memory with scope limited to the C++ mex function only, and another memory space with scope visible to the Matlab program). Otherwise, I'm not sure why Matlab is complaining about this problem.

+1  A: 

It feels like it's mexMakeMemoryPersistent() that is causing all this trouble. I guess you have to use it to instruct matlab do not delete the memory once it's done. But why should matlab delete the dasani pointer? How is that pointer provided to matlab and what does matlab need it for?

Magnus Skog
I figured out the problem, and it didn't have anything to do with how I have implemented the C++ class. It had to do with me not setting some member variables to be persistent, on top of setting the class to be persistent, causing those member variables' memory to be out of scope when the destructor is invoked.
stanigator
A: 

On top of making dasani to be a persistent pointer, I also need to make its member variables with memory allocated by mxMalloc/mxCalloc to be persistent too, for example:

if (!dasani)
{
    dasani = new NeedleUSsim;
    mexMakeMemoryPersistent((void*) dasani->tplL);
    mexMakeMemoryPersistent((void*) dasani->tplR);
    mexMakeMemoryPersistent((void*) dasani->tplRho_deg);
    mexMakeMemoryPersistent((void*) dasani->tplAlpha_deg);
    mexMakeMemoryPersistent((void*) dasani->tplBeta_deg);
    mexMakeMemoryPersistent((void*) dasani->hashTb);
    mexMakeMemoryPersistent((void*) dasani->template1D);
    mexAtExit(ExitFcn);
}

With the destructor as shown:

void NeedleUSsim::Deallocate()
{
    free((void*) tplR);  free((void*) tplL);
    free((void*) tplRho_deg); free((void*) tplAlpha_deg);
    free((void*) tplBeta_deg);
    free((void*) hashTb); 
    free((void*) template1D);
}
stanigator
Goodie! Too bad I couldn't solve it for you :) But it always better to find the reason on your own. Now go ahead and accept your own answer as the solution to your question. 15 points :)
Magnus Skog
Unfortunately, I don't think you get the 15 points for accepting your own answer. But, I think you still get the 2 points for marking an answer as "accepted", even if it is yours.
gnovice
I think I only get 15 points if more than a certain amount of users vote up on my answer, which I don't know if that would be the case. I have problems explaining the answer without going overboard in terms of content anyway.
stanigator
+4  A: 

The MEX API supports C as well as C++. Because C has no try/catch or destructors, there is no way for a C MEX-function to clean-up memory directly in the event of an error. Therefore, MATLAB tracks the results of the memory allocation routines (mxMalloc, mxCalloc, mxRealloc, mxFree, and all the mxCreate* functions that return mxArrays) on an internal list. If an error occurs during the MEX-function execution (either by calling mexErrMsgIdAndTxt directly, or using something like mexEvalString to call MATLAB code that errors), then MATLAB will automatically free any mx-based allocated memory. But, also, when a MEX-function terminates normally, MATLAB will also free any mx-based memory allocated by the MEX-function. Before the days of destructors, this was a convenience for MEX authors, though in the modern C++ world it can get really annoying.

Sometimes, as in the case of this question, you don't want MATLAB to auto-free memory. In that case, you have to use mexMakeMemoryPersistent, or mexMakeArrayPersistent for mxArrays.

You should only ever pass a pointer to mexMakeMemoryPersistent if it was originally allocated with mxMalloc, mxCalloc, or mxRealloc. So this code

dasani = new NeedleUSsim;
mexMakeMemoryPersistent((void*) dasani);

is bad with a capital 'B', unless you have overloaded NeedleUSsim::operator new() to use mxMalloc, which I wouldn't recommend. But if the fields of dasani are allocated with mxMalloc et al., then you would want to pass those to mexMakeMemoryPersistent. I'd recommend doing something like that in the NeedleUSsim constructor if at all possible, to keep it near the mxMalloc call.

SCFrench