In mex file, I can't overwrite scalar value through the pointer in matlab2016a, although I can overwrite the scalar value through the pointer in matlab2013a and I can also overwrite the array through the pointer in matlab2016a.

3 views (last 30 days)
[environment]
OS: OSX10.11 and maxOS Sierra(10.12)
MATLAB: matlab2013a and matlab2016a
Xcode: xcode7 and xcode8
------------------------------------------------------
In my work, I must use the following mex file in the old package.
//destructiveMatrixWriteAtIndices.c
//------------------------------------------------------
#include <matrix.h> /* Matlab matrices */
#include <mex.h>
#include <stddef.h> /* NULL */
#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
void mexFunction(int nlhs, /* Num return vals on lhs */
mxArray *plhs[], /* Matrices on lhs */
int nrhs, /* Num args on rhs */
const mxArray *prhs[] /* Matrices on rhs */
)
{
double *mtx;
double *newValues;
double *doubleStartIndex;
int i, startIndex, size;
mxArray *arg;
if (nrhs != 3) mexErrMsgTxt("requires 3 arguments.");
/* ARG 1: MATRIX */
arg = prhs[0];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
mtx = mxGetPr(arg);
arg = prhs[1];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
newValues = mxGetPr(arg);
size = (int) mxGetM(arg) * mxGetN(arg);
arg = prhs[2];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
doubleStartIndex = mxGetPr(arg);
startIndex = (int) doubleStartIndex[0];
for (i=0; i<size; i++)
{
mtx[i+startIndex] = newValues[i];
}
return;
}
//------------------------------------------------------
This mex file is the function to overwrite the scalar and the part of matrix through the pointer.
e.g. in matlab2013a command window (scalar in matlab2013a)
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "3".
e.g. in matlab2013a and matlab2016a command window (matrix in matlab2013a and matlab2016a)
a = [1, 2];
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "[3, 2]".
e.g. in matlab2016a command window (scalar in matlab2016a)
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "1"! Why?
I also used the lldb, and revealed the strange behavior of this code.
In matlab2013a and matlab2016a, when I run the following snippet.
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
The lldb revealed "*mtx = 3" at the end of the mex function in both matlab, but the mex function couldn't pass the result(*mtx = 3, or prhs[0] = 3) through the pointer in the only matlab2016a.
It's very strange behavior!
※I have understood that this mex function is very danger, but this mex function was used at some points in the package that I must use. Therefore, I must fix this mex file and make the package run in matlab2016a.
Please help me.
  2 Comments
James Tursa
James Tursa on 7 Oct 2016
Did you recompile this mex routine under R2016a? Or are you using the mex routine you compiled in an earlier version? I would try recompiling if you haven't yet. I would also put this statement at the end of your mex routine to verify that the double data did in fact get changed in the mex routine:
mexCallMATLAB(0,NULL,1,prhs,"disp");
What is the purpose of this mex routine? I.e., why can't you just do a regular indexed assignment at the m-file level to accomplish this? Are you trying to force in-place data replacement even if the variable is a shared-data-copy of another variable? Or what?
c0maru
c0maru on 9 Oct 2016
I already recompiled the mex routine under R2016a.
In addition, I performed the other test according to your advice.
I inserted the following code,
mexCallMATLAB(0,NULL,1,prhs,"disp");
before "retuen", recompiled the mex routine, and ran it.
The result of this test is here.
>> a = 1
a =
Structure address = 1256b5130
m = 1
n = 1
pr = 7f98bc130c00
pi = 0
1
>> destructiveMatrixWriteAtIndices(a, 3, 0)
mtx = 0x7f98ba89bde0
Structure address = 12571e6a0
m = 1
n = 1
pr = 7f98ba89bde0
pi = 0
3
>> b = [1, 2]
b =
Structure address = 1256fc720
m = 1
n = 2
pr = 7f98bbb766a0
pi = 0
1 2
>> destructiveMatrixWriteAtIndices(b, 3, 0)
mtx = 0x7f98bbb766a0
Structure address = 1256fce20
m = 1
n = 2
pr = 7f98bbb766a0
pi = 0
3 2
By this result, the problem of this code became very clear.
I had to use some old MATLAB package and I wanted to do small correction as much as possible, but now, I understood this mex routine is useless and dangerous anymore. Thus, I will rewrite some sections containing this mex routine by using normal matlab indexing.
Thank you very much.

Sign in to comment.

Accepted Answer

Philip Borghesani
Philip Borghesani on 7 Oct 2016
Scalar values no longer (as of R2015b) create mxarrays by default. They are created as needed when a mex or buit-in function is called. Run the following code as a script (or function) after calling format debug.
%script t1
a=5;
a
a
% end script
>> t1
a =
Structure address = 61963510
m = 1
n = 1
pr = aa4a51c0
pi = 0
5
a =
Structure address = 61963510
m = 1
n = 1
pr = f93815a0
pi = 0
5
Note that the pr values are different. The mex file is modifying a copy of the scalar value that is used by the MATLAB code.
  1 Comment
James Tursa
James Tursa on 7 Oct 2016
Edited: James Tursa on 7 Oct 2016
Wow ... that's interesting. The mxArray structure is the same but the data area is created on the fly for each use from some other behind-the-scenes source that you can't get at. What was the reason for this change? Some minor performance boost? Avoiding shared data copies of scalars? Or ...?
"Scalar values no longer (as of R2015b) create mxarrays by default."
Can you elaborate? Looks like the mxArray is in fact created for the scalar since the mxArray structure address is constant. It appears to me that only the data area is created on the fly (I presume to avoid shared data copies of scalars or some other very minor performance boost reason).

Sign in to comment.

More Answers (1)

James Tursa
James Tursa on 7 Oct 2016
One possibility is that MATLAB is not passing "a", but a copy of "a" to the mex routine. In my experience MATLAB always has passed the actual variables to the mex routine, but maybe this has changed and now MATLAB passes a temporary copy of scalars. Do the following to make sure you are getting the original "a" passed to the mex routine:
format debug
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
Then in the mex routine print out the address of prhs[0], e.g.,
mexPrintf("prhs[0] = %p\n",prhs[0]);
and compare this to the variable structure address that is printed out at the m-file level. They should be the same, but maybe in R2016a they aren't for some reason. Let me know what you find out. This would be a real bummer if the argument passing mechanism for mex files has changed!
  1 Comment
c0maru
c0maru on 9 Oct 2016
Edited: c0maru on 9 Oct 2016
I inserted the following code,
mexPrintf("mtx = %p\n",mtx);
after
mtx = mxGetPr(arg);
, compiled mex file, and tested it.
The result of this test is here.
>> a= 1
a =
Structure address = 12578a080
m = 1
n = 1
pr = 7f98b84daaa0
pi = 0
1
>> destructiveMatrixWriteAtIndices(a, 3, 0)
mtx = 0x7f98cc3b0900
>> b = [1, 2]
b =
Structure address = 1257ad2f0
m = 1
n = 2
pr = 7f98bc324520
pi = 0
1 2
>> destructiveMatrixWriteAtIndices(b, 3, 0)
mtx = 0x7f98bc324520
So, the advice by you was appropriate and the answer by Philip Borghesani is correct .
Thank you.

Sign in to comment.

Categories

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

Tags

Products

Community Treasure Hunt

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

Start Hunting!