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

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

Accepted Answer

James Tursa
James Tursa on 1 Mar 2021
Edited: James Tursa on 2 Mar 2021
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.

More Answers (1)

Sindhu Karri
Sindhu Karri on 1 Mar 2021
Edited: Sindhu Karri on 1 Mar 2021
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!

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Products


Release

R2020b

Community Treasure Hunt

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

Start Hunting!