Why is mxGetPi giving an Access Violation?

1 view (last 30 days)
The attached script - which is very stripped down - works until I un-comment line 48, which uses mxGetPi, at which point I am given an access violation. I managed to get this far by allocating memory for input vectors prior to using mxGetPr/Pi (if this isn't advisable, please let me know. But it does seem to eliminate access violation errors for mxGetPr). The variable 'volume' (the first rhs variable) can be taken as 1, while I am using a vector (length 100*volume) of zeros for the second rhs input, and a vector of length 100*volume of ones for the 3rd rhs input.
How can I prevent an access violation when using mxGetPi?
#include "mex.h"
void test_function(double *out_mat,long int volume,
double *Mx_in,double *My_in,double *Mz_in)
{
long int k;
double Mxyz[3];
for (k=0; k <= 100*volume-1; ++k)
{
Mxyz[0] = Mx_in[k];
Mxyz[1] = My_in[k];
Mxyz[2] = Mz_in[k];
out_mat[k] = Mxyz[0] + Mxyz[1] + Mxyz[2];
}
}
/*************************************************************************/
// MEX FUNCTION HERE //
/*************************************************************************/
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nlhs != 1){
mexErrMsgTxt("ERROR: Number of arguments does not equal 9. \n");
}
if (nrhs != 3){
mexErrMsgTxt("ERROR: Number of RHS objects is incorrect. \n");
}
double volume;
volume = mxGetScalar(prhs[0]);
double *Mx_in;
double *My_in;
double *Mz_in;
Mx_in = mxMalloc(sizeof(double) * 100*volume);
My_in = mxMalloc(sizeof(double) * 100*volume);
Mz_in = mxMalloc(sizeof(double) * 100*volume);
Mx_in = mxGetPr(prhs[1]);
Mz_in = mxGetPr(prhs[2]);
/* My_in = mxGetPi(prhs[1]); */
double *out_mat;
plhs[0] = mxCreateDoubleMatrix(100*volume,1,mxREAL);
out_mat = mxGetPr(plhs[0]);
test_function(out_mat,volume,Mx_in,My_in,Mz_in);
}

Accepted Answer

James Tursa
James Tursa on 24 Aug 2016
Edited: James Tursa on 24 Aug 2016
Some comments on your use of pointers and memory allocation:
Mx_in = mxMalloc(sizeof(double) * 100*volume); <-- Delete this line, it is leaked
My_in = mxMalloc(sizeof(double) * 100*volume);
Mz_in = mxMalloc(sizeof(double) * 100*volume); <-- Delete this line, it is leaked
Mx_in = mxGetPr(prhs[1]); <-- Creates a memory leak, loses the previous Mx_in
Mz_in = mxGetPr(prhs[2]); <-- Creates a memory leak, loses the previous Mz_in
/* My_in = mxGetPi(prhs[1]); */ <-- Only makes sense if the 2nd input is complex
So, if the 2nd input is real, then the result of mxGetPi(prhs[1]) will be NULL. So when you pass this into your test_function routine and access My_in[k] you will get an access violation and a crash. The reason your My_in = mxMalloc(etc) fixes that crash is because with this line added My_in now points to valid (but uninitialized) memory.
I can't really advise you what to do about My_in because I don't know what your code is supposed to do. Maybe you could put in some comments about what each input to the mex routine is, and what the calculation is supposed to be for the result. Then I could advise you on how to code it properly.
Also, I would change this check:
if (nlhs != 1){
mexErrMsgTxt("ERROR: Number of arguments does not equal 9. \n");
}
to this:
if (nlhs > 1){
mexErrMsgTxt("ERROR: Too many outputs. \n");
}
The way you have it coded, it forces the user to assign the mex output to a variable and doesn't allow then to simply call the mex function and have the result returned into ans. Even if nlhs==0, there is always room for one output to be placed in plhs[0] (so it can be returned into ans).
Also, at some point you should put in input argument checks to make sure they are the expected class, size, complexity, sparsity, etc so your code will not crash for unexpected inputs.
  2 Comments
Michael Mullen
Michael Mullen on 24 Aug 2016
Edited: Michael Mullen on 24 Aug 2016
Okay, I didn't realize that's what it was doing, so thank you! I am still learning about memory access/allocation.
Of course I can give some details! It is a stripped down version of a Bloch simulator - if you're not familiar with physics, they're really common in MRI/NMR physics are used to model the magnetization of some sample with a given set of magnetic field gradients, radiofrequency pulses, etc. I stripped it down so anyone helping wouldn't have to worry about what the rest of the code was doing, because I did manage to narrow it down to what I had posted. Getting to your suggestion about details, the second input, prhs[1], is supposed to be the component of the magnetization vector in the x-y plane, represented as a complex number. Generally speaking then, every entry can be complex, but isn't guaranteed to be at all times. For prhs[2], this vector is the z-component of the magnetization, which always real, and after removing the memory allocations, it still works, so I'm banking on this not being an issue anymore.
I'm doing things in kind of a funny way, because I am trying to run my simulation with a large number of points in a 2D grid (~640^2) running through around 8200 time points. I don't know how much memory that requires in RAM, but I have had issues with much smaller arrays, so I'm opting to take one slice in time, compute the next slice, save the old one to disc, then remove it from memory.
Getting to what it is supposed to do: what I called out_mat is just a bogus function to make things simpler. I haven't had any issues with outputs, but in general there will be a fair bit of calculation and then a complex number will be saved to one output, and a real to another output. I know I don't have that coded into what I posted, but I was trying to strip it down as much as possible to isolate the issue I was having.
That was long winded, so my next question would be: instead of mxGetPi returning NULL, how would I get it to return a vector of zeros? Or would I simply need an if(mxGetPi(prhs[1]) == NULL){make vector of zeros here}? Also, what happens if some, but not all, of the entries of prhs[1] have no imaginary component? I guess I could go test that.
Finally, thank you for the other tips! I'm getting to argument checks, eventually...
**UPDATE***** I answered my own question: as long as at least one entry is complex, mxGetPi does fine, it seems like! The output is as expected for the complex entries, and doesn't have any access violations.
James Tursa
James Tursa on 24 Aug 2016
Yes, I think you got it now. If at least one of the elements of prhs[1] is complex, then there will be memory allocated for the imaginary data behind mxGetPi(prhs[1]) that is the same size as the real data behind mxGetPr(prhs[1]). Of course, some of those imaginary components might be 0. To check to see if prhs[1] is complex:
mxIsComplex(prhs[1])
does the same thing as
mxGetPi(prhs[1]) != NULL
If this test fails (meaning prhs[1] is in fact real and not complex) then your code would have to handle that case. E.g., allocate a temporary 0-filled vector to be used by your downstream code, or have different code for this case.

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!