mexCallMATLAB Memory Leak / mxDestroyArray / C++ Crashing

4 views (last 30 days)
I'm having trouble using mexCallMATLAB in the code below. I'm successfully feeding in the x,y,z coordinates and corresponding normal vectors into the Matlab function (as I can stop and debug the file check_occ_curve.m). But I think something in my mxDestroyArray calls is causing a crash.
My chain of reasoning here is basically to copy all the points into a new array x_p, because the points stored in the point cloud model are integers (model.pts[i].x is the x coordinate of the ith point, similarly for y and z, and model.normals[i].x is the x component of the normal vector at point i). Then I fill in pts_and_normals, which contains (the pointers to) three mxArrays, where I store the pointers for this new data. Then I want to destroy the arrays once I'm done with the mexCallMATLAB call, but I'm reasonably sure that the crash is occurring at an mxDestroyArray or because of some sort of memory leak on something that I should be destroying but am not.
Comment 1: When I run the following WITH the line mxDestroyArray(ppLhs[0]) and mxDestroyArray(ppLhs[1]), I get a crash (and one member of the stack trace is: "...mx_array_api31try_nonrecursive_mxDestroyArrayEP11mxArray_tag+00000015.")
Comment 2: But when I remove the lines mxDestroyArray(ppLhs[0]) and mxDestroyArray(ppLhs[1]) and add mxSetData(pts_and_normals[0], NULL); mxSetData(pts_and_normals[1], NULL); mxSetData(pts_and_normals[2], NULL); the stack trace is more mysterious, the line after the call to occ_curve.cpp (which is the function that calls this method) in the stack trace is "<unknown-module>+00000000."
When I remove the mxSetData and mxDestroyArray(ppLhs[0]),... . The stack trace again contains: "try_nonrecursive_mxDestroyArrayEP11mxArray_tag+00000015."
Does anyone have any ideas how I can fix this? The crash MUST be happening AFTER the mexCallMATLAB line (because I can stop that .m file in the Matlab debugger), so I think it's either a memory leak/problem (much more likely) or some sort of problem in the way I'm assigning or saving the output data from mexCallMATLAB.
  2 Comments
Jeremy
Jeremy on 8 Nov 2015
Edited: Jeremy on 8 Nov 2015
Sorry to not include this code in the first post (This is my 10th or so attempt to post this, I kept getting the error "Bad Request
Your browser sent a request that this server could not understand.")
void projection::matlab(ptcloud model){
R = model.R;
nl = model.num_el/3;
mxArray *x_p, *x_n;
//array of floats?
mwSignedIndex dims[2];
dims[0] = nl*3;
dims[1] = 1;
// array of points, where point i has x coordinate x_p(3*i), y coordinate x_p(3*i + 1) and z coordinate x_p(3*i + 2)
x_p = mxCreateNumericArray(2,dims,mxSINGLE_CLASS,mxREAL);
// array of the corresponding normal vectors, where point i has normal vector with
// x component x_p(3*i), y coordinate x_p(3*i + 1) and z coordinate x_p(3*i + 2)
x_n = mxCreateNumericArray(2,dims,mxSINGLE_CLASS, mxREAL);
mwSignedIndex dims2[2];
dims2[0] = 2;
dims2[1] = 1;
mxArray *xy_size_of_image;
xy_size_of_image = mxCreateNumericArray(2,dims2,mxINT32_CLASS, mxREAL);
int xy_cpp_size[2];
xy_cpp_size[0] = X_Size;
xy_cpp_size[1] = Y_Size;
// xy_size_of_image is is used to send the x and y dimensions of the image to the matlab function
// xy_size_of_image[0] is the number of columns
// xy_size_of_image[1] is the number of rows
memcpy( mxGetPr(xy_size_of_image) , &xy_cpp_size[0] , sizeof(int)*2);
mxArray *pts_and_normals[3];
pts_and_normals[0] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[1] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[2] = mxCreateDoubleMatrix(1,1,mxREAL);
// copy in the actual points
memcpy( mxGetPr(x_p) , &model.pts[0].x , sizeof(float)*nl*3);
// copy in the actual normal vectors
memcpy( mxGetPr(x_n) , &model.normals[0].x , sizeof(float)*nl*3);
pts_and_normals[0] = x_p;
pts_and_normals[1] = x_n;
pts_and_normals[2] = xy_size_of_image;
mxArray *ppLhs[2];
// Call the matlab function check_occ_curve( xyz, xyz_n, dimensions)
mexCallMATLAB(2, ppLhs ,3,pts_and_normals,"check_occ_curve");
n_oc = (int) *mxGetPr(ppLhs[0]);
for(int i=0; i<n_oc ; i++){
oc_ind[i]= (int) *(mxGetPr(ppLhs[1]) + i * sizeof(double));}
// see comment 1
// mxSetData(pts_and_normals[0], NULL);
// mxSetData(pts_and_normals[1], NULL);
// mxSetData(pts_and_normals[2], NULL);
// see comment 2
// mxDestroyArray(ppLhs[0]);
// mxDestroyArray(ppLhs[1]);
mxDestroyArray(pts_and_normals[0]);
mxDestroyArray(pts_and_normals[1]);
mxDestroyArray(pts_and_normals[2]);
mxDestroyArray(x_p);
mxDestroyArray(x_n);
mxDestroyArray(xy_size_of_image);
Jeremy
Jeremy on 8 Nov 2015
Edited: Jeremy on 8 Nov 2015
Update: It's (almost) definitely a memory management thing, as I changed the output assignments to the following (and I still get the same crash stack trace):
// n_oc = (int) *mxGetPr(ppLhs[0]);
n_oc = 2714;
for(int i=0; i<n_oc ; i++){
// oc_ind[i]= (int) *(mxGetPr(ppLhs[1]) + i * sizeof(double));
oc_ind[i]=i;
}
(Note that when this code is called, n_oc is 2714 at the end of the Matlab function check_cc_curve.m, so I just hard coded it. And the indices in oc_ind being incorrect _ shouldn't_ crash the code, at least not in this function.
Update 2: (part of) the actual stack trace is below:
(So I'm also wondering if maybe when I'm trying to delete x_p, which is supposed to be a _ copy_ of all the coordinates in the ptcloud model)
[ 14] 0x000000010b62487f /Applications/MATLAB_R2015b.app/bin/maci64/libmx.dylib+00043135 _ZN6matrix6detail10noninlined12mx_array_api31try_nonrecursive_mxDestroyArrayEP11mxArray_tag+00000015 [ 15] 0x00000001256af153 /.../occ_curve.mexmaci64+00012627 _ZN10projection6matlabE7ptcloud+00000483
I realize it's ridiculous at this point, but update 3: I think the problem is that I'm trying to destroy x_p, x_n and xy_size_of_image when I call mxDestroyArray(pts_and_normals[0]); mxDestroyArray(pts_and_normals[1]); mxDestroyArray(pts_and_normals[2]);
But then I ALSO still need to destroy the pts_and_normals mxArray itself, which may be the problem.(Though I still haven't worked out the solution)

Sign in to comment.

Accepted Answer

James Tursa
James Tursa on 8 Nov 2015
Edited: James Tursa on 8 Nov 2015
Some comments:
1) The signature for mxCreateNumericArray shows the dims argument as being mwSize, not mwSignedIndex. So this could be a mismatch causing problems. Change these lines to:
mwSize dims[2];
:
mwSize dims2[2];
2) I don't see R or n1 defined anywhere. Are they global?
3) First you create three mxArray's and stuff them into an array:
pts_and_normals[0] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[1] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[2] = mxCreateDoubleMatrix(1,1,mxREAL);
Then you almost immediately replace this with something else, which LEAKS the original mxArray memory above:
pts_and_normals[0] = x_p;
pts_and_normals[1] = x_n;
pts_and_normals[2] = xy_size_of_image;
Then at the end of your code you destroy the same mxArray's twice, since they are pointing to the same thing:
mxDestroyArray(pts_and_normals[0]);
mxDestroyArray(pts_and_normals[1]);
mxDestroyArray(pts_and_normals[2]);
mxDestroyArray(x_p);
mxDestroyArray(x_n);
mxDestroyArray(xy_size_of_image);
That 2nd set of mxDestroyArray calls will crash MATLAB since they were already destroyed by the first three lines.
4) This line looks very strange to me and is likely an error:
oc_ind[i]= (int) *(mxGetPr(ppLhs[1]) + i * sizeof(double));
The result of the mxGetPr call is of type "pointer to double". Adding i to it will automatically do pointer arithmetic (i.e., add 8 to the address). Multiplying it by sizeof(double) is probably not what you intended since that would skip every 8 elements and I am assuming run off the end of the array causing a crash. I am guessing this is what you want:
oc_ind[i]= (int) *(mxGetPr(ppLhs[1]) + i);
5) You haven't posted enough code for me to double check your memcpy stuff, since I have no way to determine the types involved.
  4 Comments
Jeremy
Jeremy on 8 Nov 2015
Edited: Jeremy on 8 Nov 2015
And this is where the points in the ptcloud are set
void ptcloud::set_ptcloud(double *pt_ar, double *norm_ar, double *omodel_ar, double *R_init)
{
int j = 0;
matrix3D temp(R_init[0],R_init[3],R_init[6],
R_init[1],R_init[4],R_init[7],
R_init[2],R_init[5],R_init[8]);
R = temp;
for(int i = 0; i<num_el; i+=3){
pts[j] = vector3D((float)pt_ar[i],(float)pt_ar[i+1],(float)pt_ar[i+2]);
normals[j] = vector3D((float)norm_ar[i],(float)norm_ar[i+1],(float)norm_ar[i+2]);
omodel[j] = vector3D((float)omodel_ar[i],(float)omodel_ar[i+1],(float)omodel_ar[i+2]);
++j;
}
}
Actually, I think the NaN error is because I forgot to assign a global variable in the function in which I call this method. I'm trying to replace 4 c++ methods with one Matlab file.
Something is still not working (the output somewhere is wrong, but the code isn't crashing), but I don't think the problem is in the above c++ code at this point. I'll have to hunt for bugs in the rest of the code now. Thanks for your help again!
James Tursa
James Tursa on 9 Nov 2015
Edited: James Tursa on 9 Nov 2015
Looks like you are off in debug land looking for logical errors in the code, so I will leave that to you for the moment. But you did have the following question that I will comment on:
" 3) pts_and_normals is an array of mxArrays, each of the three entries contains a mxArray with a pointer to the first element of x_p, x_n and the dimensions respectively. Don't I want to destroy the x_p, x_n and xy_size_of_image mxArrays AS WELL AS pts_and_normals? (I trust your answer, I'm just trying to understand why :) ) "
Your latest posted code has the following:
mxArray *pts_and_normals[3];
pts_and_normals[0] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[1] = mxCreateDoubleMatrix(1,1,mxREAL);
pts_and_normals[2] = mxCreateDoubleMatrix(1,1,mxREAL);
:
:
pts_and_normals[0] = x_p;
pts_and_normals[1] = x_n;
pts_and_normals[2] = xy_size_of_image;
:
mxDestroyArray(pts_and_normals[0]);
mxDestroyArray(pts_and_normals[1]);
mxDestroyArray(pts_and_normals[2]);
The first three assignments cause three new mxArray structures to be allocated, and the pointers to them saved in the pts_and_normals array. They are each scalar doubles, with the scalar value being 0.0.
The second three assignments overwrite those first three pointers with completely different pointers, namely the pointers for x_p, x_n, xy_size_of_image. This act of overwriting the previous pointers in the pts_and_normals array means that you have completely lost those original pointers ... the memory behind them gets leaked because you now have no record of them in your code. Now, since this is a MATLAB mex routine it turns out that those first three original pointers are on the garbage collection list, so when the mex routine returns back to the caller the memory will get free'd ... so you are saved by MATLAB in this case and the memory is not permanently leaked, it is only leaked until the mex function returns. In any event, at this point in your code you have two sets of pointers that point to the same exact mxArray structures. That is why you can't call mxDestroyArray on both of them. As soon as you call mxDestroyArray on one of the sets, the other set is invalid. You could get the same result, without the temporary leaking, simply by removing that first set of assignments since you apparently don't use those mxArray's for anything anyway. E.g.,
mxArray *pts_and_normals[3];
// pts_and_normals[0] = mxCreateDoubleMatrix(1,1,mxREAL);
// pts_and_normals[1] = mxCreateDoubleMatrix(1,1,mxREAL);
// pts_and_normals[2] = mxCreateDoubleMatrix(1,1,mxREAL);
:
:
pts_and_normals[0] = x_p;
pts_and_normals[1] = x_n;
pts_and_normals[2] = xy_size_of_image;
:
mxDestroyArray(pts_and_normals[0]);
mxDestroyArray(pts_and_normals[1]);
mxDestroyArray(pts_and_normals[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

Community Treasure Hunt

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

Start Hunting!