Why `mxGetField` could not be assigned to output of c mex?

조회 수: 2 (최근 30일)
wei zhang
wei zhang 2021년 2월 26일
편집: James Tursa 2021년 3월 2일
I am learning to compile mex with struct. I found a confusing problem. When I use mxGetField to assign the output of my mex, the Matlab crashed. When I use mxDuplicateArray as an intermediated step, the mex works. Could anyone tell me the reason of it? The type of prhs[0] and the return type of mxGetField are both mxArray*. Why they don't match? I know the below code is meaning less, I just would like to know the code rule.
void mexFunction(int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[])
{
mxArray *b= mxGetField(prhs[0],0,"b");
plhs[0] = mxDuplicateArray(b);
} % it works
void mexFunction(int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[])
{
plhs[0]= mxGetField(prhs[0],0,"b");
} % Matlab crashed
My input is
a.b = 1;
x = testMex(a);

채택된 답변

James Tursa
James Tursa 2021년 3월 1일
편집: James Tursa 2021년 3월 2일
The reason this crashes is because you have created a copy of an mxArray variable without telling the MATLAB Memory Manager that you did so. So when MATLAB subsequently clears one of these it invalidates the other, and then when MATLAB tries to use or clear the other it accesses invalid memory and crashes. I.e.,
plhs[0]= mxGetField(prhs[0],0,"b");
The above gets the the mxArray pointer from prhs[0] and assigns this exact pointer to plhs[0] ... essentially a reference copy. So now there is an extra reference copy of prhs[0] in the system but the MATLAB Memory Manager doesn't know about it. Eventually downstream in your code all of these copies get cleared, but on the next to last one MATLAB thinks all the copies are cleared so it releases the memory. Then when it tries to use or clear the last one it accesses invalid memory and crashes.
The same thing would happen if you tried to copy an mxArray pointer from one cell or struct array element into another element, either in the same or a different cell or struct array. This would in essence create a reference copy of the variable without telling the MATLAB Memory Manager about it. MATLAB will crash downstream at some point when these variables are cleared. This practice could be done safely if you were to bump up the reference count of the variable each time you made a new assignment, but this requires mxArray hacks because there is no API function to do this.
There are three ways to extract an mxArray variable from a cell or struct variable and assign it to a plhs[ ] variable. Assuming you have already checked that nrhs >= 1 and that mxGetField(prhs[0],0,"b") is not NULL:
1) The only official way, which creates a deep copy:
plhs[0] = mxDuplicateArray(mxGetField(prhs[0],0,"b"));
This is the only method that is officially supported and will likely not break in the future. The downside is that if you are working with very large variables it can be a tremendous waste of time and memory to create this deep copy.
2) Using an unofficial API function to create a shared data copy:
plhs[0] = mxCreateSharedDataCopy(mxGetField(prhs[0],0,"b"));
This method is very fast and is useful for large variables. But this method requires you to jump through some hoops, and it may break in the future if they remove this function from the API library. Details for using it can be found in the header file here:
3) Bump up the reference count:
plhs[0] = mxCreateReference(mxGetField(prhs[0],0,"b"));
This method is also very fast and useful for large variables. This function used to be in the API library, and the only thing needed to use it was a prototype. However, this function was removed from the API library back in R2014a. So the only way to do this now is to hack into the mxArray itself. This is tricky to do since the mxArray definition and the location of the reference count field has changed over the years. Also the rules for how MATLAB handles the plhs[ ] variables are not published so it is unclear if this will even work for a sub-array type variable instead of a temporary variable. Although this would be the obvious method to use when copying cell or struct field variables from one cell or struct array to another cell or struct array, I wouldn't advise this option for assigning to the plhs[ ] array variables. I would advise method 2 instead for plhs[ ] array variable assignment.
Note that MATLAB itself generally uses either method 2 or 3 in the background when you are working at the m-file level, but for some reason has not made these methods official for mex programmers.
  댓글 수: 1
wei zhang
wei zhang 2021년 3월 2일
Very glad to know mxCreateSharedDataCopy and mxCreateReference functions!

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Sindhu Karri
Sindhu Karri 2021년 3월 1일
편집: Sindhu Karri 2021년 3월 1일
Hii,
You have to allocate memory to plhs[0] before assigning a value to it.mxGetField directly assigns value whereas mxDuplicateArray does both memory allocation and value assignment,which the correct way to assign values to output pointer plhs[0].So,MATLAB crashes when mxGetField is used.
Hope this answers your question!

카테고리

Help CenterFile Exchange에서 Write C Functions Callable from MATLAB (MEX Files)에 대해 자세히 알아보기

제품


릴리스

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by