1 view (last 30 days)

Show older comments

[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.

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.

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).

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!

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

Start Hunting!