malloc error when making multiple subsequent calls to mex file

I wrote a mex file in C to simulate lattice dynamics. I can call the mex function once without any errors. However, when I make a subsequent calls to the function I get the following malloc error and matlab crashes:
MATLAB_maci64(1722,0x10ea01000) malloc: *** error for object 0x6000001c0940: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug (lldb)
Sometimes the error occurs on the second call, but it will often take a couple more calls. I tried using a malloc_error_break breaking point while debugging with Xcode but it doesn't catch on anything. I posted my (awful-looking) C code bellow.
Should I be freeing memory at one point in the mex function?
I am a beginner in both C and Matlab code, so I don't have a very good understanding of memory management, especially for mex functions.
Thank you for your time,
Best,
Julien
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <matrix.h>
#include <mex.h>
//Computation function
void Lat_dynam(const int N_l,
const int R_l,
const int det_k_l,
double *Bed_init_l,
double *Bed_out_l,
double *Det_out_l,
double *Rel_out_l,
const double pStabil_l,
const double pRecover_l,
const double pDisturb_l,
const double pDist_ini_l,
const double rho_l,
const int det_effect_l)
{
//Declare local variables not received as input
mwSize i, j, l, k, n, update, step, seed;
int m, d, o;
double n_Occ, n_Dist, pDisturb_real, r;
//Disturbance/recovery operations on random cells
seed = 1456739853;
srand48(seed);
m = (int)(drand48()*(N_l*N_l));
for (i=0; i<(int)(N_l*N_l); i++){
Bed_out_l[i] = Bed_init_l[i];
}
for (step=1; step<(int)(R_l+1); step++){
for (update=1; update<(int)(2); update++){
//Compute neighborhoods
d = 0;
o = 0;
//select random lattice cell
if (Bed_out_l[m+(step-1)*N_l*N_l]!=0) {
//Neighbourhood assessment with periodic boundary conditions
for (j=(m-N_l); j<(int)(m+N_l+2); j=j+N_l){ //Navigate columns
if (j<((step-1)*N_l*N_l)){
j=step*(N_l*N_l)-N_l+m;
}
else if (j>=(step*N_l*N_l)){
j=((step-1)*N_l*N_l)+(N_l-(N_l*N_l)-m);
}
for (l=j-1; l<(int)(j+2); l++){ //Navigate rows
if (((l+1)%N_l) == 0 && l == (j-1)){
l=l+N_l; //Same row position but on the following column
}
else if (l%N_l == 0 && l == (j+1)){
l=l-N_l; //Same row position but on the previous column
}
if (Bed_out_l[m+(step-1)*N_l*N_l]==0){
if (l==m){
//Do nothing (exclude updated cell from n_Dist calculation)
}
else{
d++;
}
}
else if (Bed_out_l[m+(step-1)*N_l*N_l]==2){
if (l==m){
//Do nothing (exclude updated cell from n_Occ calculation)
}
else{
o++;
}
}
}
}
}
//Neighbourhoods occupancy
n_Dist = d/8; //Note that n_dist is a proportion of the neighbourhood (not like in Fred's article where it is either 0 or 1)
n_Occ = o/8;
//Update lattice cell state
r=drand48(); //generate random number for state transition evaluation
if (Bed_out_l[m+(step-1)*N_l*N_l]==0){
if (r<=(pStabil_l)){
Bed_out_l[m+(step-1)*N_l*N_l]=1; //stabilization of edge of Disturbed cells
}
}
else if (Bed_out_l[m+(step-1)*N_l*N_l]==1){
if (r<=(pRecover_l*n_Occ)){
Bed_out_l[m+(step-1)*N_l*N_l]=2; //recovery of empty cells using pRecover probability
}
}
else{
if (det_effect_l==0){
pDisturb_real=pDisturb_l*n_Dist*k;
}
else if (det_effect_l==1){
pDisturb_real=pDisturb_l*n_Dist*det_k_l*Bed_out_l[m+(step-1)*N_l*N_l];
}
if (r<=(pDisturb_l*n_Dist*k*+pDist_ini_l)){ //Disturbance of occupied cells using pDisturb proability
Bed_out_l[m+(step-1)*N_l*N_l]=0;
Rel_out_l[update+(step-1)*N_l*N_l]=Det_out_l[m+(step-1)*N_l*N_l]; //Store how much det was released
Det_out_l[m+(step-1)*N_l*N_l]=0; //Reset Det to 0 for this cell.
}
else{
Det_out_l[m+(step-1)*N_l*N_l]=Det_out_l[m+(step-1)*N_l*N_l]+rho_l; //Acretion of detritus
}
}
}
//Copy lattice at the end of the updates cycle
for (n=0; n<(int)(N_l*N_l); n++){
Bed_out_l[(step*N_l*N_l)+n] = Bed_out_l[((step-1)*N_l*N_l)+n];
}
}
}
// Gateway (mexFunction) MATLAB uses as an entry point in the program
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
//Declare variables
/*Note: all the following variables are local to the mexFunction,
will receive their values from prhs[#] variables and be passed to Lat_dynam*/
double *Bed_init, *Bed_out_m, *Rel_out_m, *Det_out_m, pRecover, pDisturb, pStabil, rho, pDist_ini, det_k, det_effect;
int N, R;
//Associate scalar variables to the pointer contained in mxArray
N = mxGetScalar(prhs[0]);
R = mxGetScalar(prhs[1]);
det_k = mxGetScalar(prhs[2]);
pRecover = mxGetScalar(prhs[3]);
pDisturb = mxGetScalar(prhs[4]);
pStabil = mxGetScalar(prhs[5]);
pDist_ini = mxGetScalar(prhs[9]);
rho = mxGetScalar(prhs[6]);
Bed_init = mxGetPr(prhs[7]);
det_effect = mxGetScalar(prhs[8]);
//Dimensions of inputed and output matrices Bed_out_m, Det_out_m, and Rel_out_m
mwSize dims[3] = {N,N,R};
mwSize dims_Rel[2] = {R,N};
//Create output matrices
plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
plhs[1] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
plhs[2] = mxCreateNumericArray(2, dims_Rel, mxDOUBLE_CLASS, mxREAL);
//Get pointer to real data in output matrices
Bed_out_m = mxGetPr(plhs[0]);
Det_out_m = mxGetPr(plhs[1]);
Rel_out_m = mxGetPr(plhs[2]);
//Run Lat_dynam
Lat_dynam(N,
R,
det_k,
Bed_init,
Bed_out_m,
Det_out_m,
Rel_out_m,
pStabil,
pRecover,
pDisturb,
pDist_ini,
rho,
det_effect);
}

1 Comment

I should also specify the multiple calls to the mex function are made using the same input values (and the same seed for the PRNG withing the C code).

Sign in to comment.

Answers (1)

First thing I noticed was these lines:
int dims[3] = {N,N,R};
int dims_Rel[2] = {R,N};
:
plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
plhs[1] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
plhs[2] = mxCreateNumericArray(2, dims_Rel, mxDOUBLE_CLASS, mxREAL);
The signature for mxCreateNumericArray calls for a (mwSize *) type as the 2nd argument. On a 64-bit machine this could be 8-byte integers. You are using (int *) however, which may be 4-byte integers on your machine. I would first make this change:
mwSize dims[3] = {N,N,R};
mwSize dims_Rel[2] = {R,N};
Second thing I noticed is that you don't appear to be initializing things properly. E.g., this code:
int dims[3] = {N,N,R};
:
plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
:
Bed_out_m = mxGetPr(plhs[0]);
:
Then inside the Lat_dynam function you have:
for (i=0; i<(int)(N_l*N_l); i++){
Bed_out_l[i] = Bed_init_l[i];
}
:
if (Bed_out_l[m+(step-1)*N_l*N_l]!=0) {
So, Bed_out_m points to a NxNxR sized array, but inside the Lat_dynam function you are only initializing the first NxN slice to Bed_init_l, not the entire NxNxR array. I don't know if this is intentional or not.
Also, downstream in the code you use the variable m in your indexing, but m is not set anywhere. So you are using an uninitialized variable (garbage value) in your indexing. This could cause the index to be out of bounds and result in a memory error.
Third thing I noticed is that you are mixing some mwSize and int calculations. mwSize might very well reduce to a size_t type, which is an unsigned integer. So mixing calculations with these might not yield the answer you were expecting because of signed/unsigned conversions going on in the background. I would double check all of your integer calculations to see if this might be a problem.

7 Comments

Hi James,
Thank you for your help and pointing out the use of int instead of mwSize. I corrected it.
It is intentional that only the first NxN slice is initialized to Bed_init_l, as the following NxN slices represent subsequent time steps which will be allocated by the computing routine under:
//Update Lattice cell state
The variable m is initialized in the original code using:
m = (int)(drand48()*(N_l*N_l));
but I accidentally removed this line when copying the code.
Being a beginner, I don't understand what is wrong with these lines however:
int dims[3] = {N,N,R};
:
plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
:
Bed_out_m = mxGetPr(plhs[0]);
:
Again, thank you very much for your time and your help, I understand that my code is messy and not easy to explore.
Julien
If the mistake is in the index calculations, check each one before using it to make sure it is in bounds. Also, check all of your inputs to make sure they are the expected size.
You are right, I should and will check the inputs size and the indexes right now. However, I would like to point out that the malloc error will occur when using the exact same inputs for the mex function call, and never on the first call.
The behavior you are experiencing is not unusual for memory errors. The first call corrupts memory but doesn't yet result in a crash (maybe because the corrupted memory doesn't get used by anything else yet). The second call results in a crash because the corrupted memory actually gets used by something else for some reason behind the scenes (memory manager checking, etc).
E.g., and I am just guessing here, you could be writing off the end of an array and corrupting the header information of a mxArray that is nearby in memory. One of the items corrupted could be a data pointer that was originally allocated with malloc. Then later on MATLAB attempts to clear that mxArray variable from memory. So one of the first things it does is free the memory behind the data pointer. It grabs the corrupted data pointer and passes it to free( ), which checks the data pointer, does not find it on the internal list of allocated memory blocks, and promptly crashes as a result. Bottom line is, memory errors can result in all kinds of weird (bad) behavior.
Thank you for explaining, it makes more sense to me now. So I guess setting up check points for inputs and indexes is my best bet for now.
I was also wondering if there is anything in the way I use pointers and mxCreate* functions that could generate malloc memory errors?
I don't see any direct use of malloc or free in your code, so I am just guessing as to the cause of the error you are getting (i.e., some generic memory writing error). In particular, I don't see anything obviously wrong with your use of mxCreateNumericArray or mxGetPr.
I did notice, however, that Rel_out_m points to a RxN matrix. But in your code you access it like this:
Rel_out_l[update+(step-1)*N_l*N_l]
So it looks like the indexing used assumes pages of size NxN which doesn't look right based on the allocated size. You might check into this.
Ok, I wanted to double check the code for such mistakes but didn't realize it could induce memory errors. I will do my homeworks and clean-up the code before asking any more questions.
Thanks a lot for the help and tips,
Best,
Julien

Sign in to comment.

Categories

Asked:

on 6 Jul 2015

Commented:

on 6 Jul 2015

Community Treasure Hunt

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

Start Hunting!