Segmentation error in mex file

1 view (last 30 days)
abc
abc on 22 Jan 2014
Edited: abc on 23 Jan 2014
Here is the mex code I wrote to read in a tab-delimited file. The mex file got created but it causes my MATLAB to end abruptly and give the following error. Can anyone help me where I am going wrong? Please let me know if any further information is required. I have attached the error report though I do not know if it can help
Abnormal termination: Segmentation violation
#include "mex.h"
#include "matrix.h"
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
FILE *ptr_file;
const char **field_names; /* pointers to field names */
char *buf[1024];
char *temp[20];
int count;
int i, j, k, l;
int date_field, mva_field, qc_load_field, air_field, qc_air_field, oil_field, qc_oil_field, wind_a_field, qc_wind_a_field, wind_b_field, qc_wind_b_field, wind_c_field, qc_wind_c_field, tamb1_field, qc_tamb1_field;
char *NAME;
NAME=mxArrayToString(prhs[0]);
count = 0;
//open file to count elements
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start counting no. of elements
while(fgets(buf, sizeof(buf), ptr_file) != NULL)
count++;
fclose(ptr_file);
}
field_names[0] = "date";
field_names[1] = "mva";
field_names[2] = "qc_load";
field_names[3] = "air";
field_names[4] = "qc_air";
field_names[5] = "oil";
field_names[6] = "qc_oil";
field_names[7] = "wind_a";
field_names[8] = "qc_wind_a";
field_names[9] = "wind_b";
field_names[10] = "qc_wind_b";
field_names[11] = "wind_c";
field_names[12] = "qc_wind_c";
field_names[13] = "tamb1";
field_names[14] = "qc_tamb1";
plhs[0] = mxCreateStructMatrix(count, 1, 15, field_names);
plhs[1] = mxCreateDoubleMatrix(1,1,mxREAL);
date_field = mxGetFieldNumber(plhs[0],"date");
mva_field = mxGetFieldNumber(plhs[0],"mva");
qc_load_field = mxGetFieldNumber(plhs[0],"qc_load");
air_field = mxGetFieldNumber(plhs[0],"air");
qc_air_field = mxGetFieldNumber(plhs[0],"qc_air");
oil_field = mxGetFieldNumber(plhs[0],"oil");
qc_oil_field = mxGetFieldNumber(plhs[0],"qc_oil");
wind_a_field = mxGetFieldNumber(plhs[0],"wind_a");
qc_wind_a_field = mxGetFieldNumber(plhs[0],"qc_wind_a");
wind_b_field = mxGetFieldNumber(plhs[0],"wind_b");
qc_wind_b_field = mxGetFieldNumber(plhs[0],"qc_wind_b");
wind_c_field = mxGetFieldNumber(plhs[0],"wind_c");
qc_wind_c_field = mxGetFieldNumber(plhs[0],"qc_wind_c");
tamb1_field = mxGetFieldNumber(plhs[0],"tamb1");
qc_tamb1_field = mxGetFieldNumber(plhs[0],"qc_tamb1");
//open file again for storing elements columnwise
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start collecting data
for(i=0;i<count;i++){ //increment line
//get line
fgets(buf, sizeof(buf), ptr_file);
j=0;
k=0;
//extract first word
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
mxSetFieldByNumber(plhs[0],i,date_field,mxCreateString(temp));
// strcpy(elem[i].date, temp);
//extract second word
k=0;
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
// elem[i].mva = atof(temp);
*mxGetPr(plhs[1]) = atof(temp);
mxSetFieldByNumber(plhs[0],i,mva_field,plhs[1]);
//extract third word
k=0;
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
// strcpy(elem[i].qc_load, temp);
mxSetFieldByNumber(plhs[0],i,qc_load_field,mxCreateString(temp));
// similarly for other fields of the structure.
fclose(ptr_file);
}
}

Accepted Answer

James Tursa
James Tursa on 23 Jan 2014
Edited: James Tursa on 23 Jan 2014
I don't see anywhere where you allocate field_names:
const char **field_names; /* pointers to field names */
:
field_names[0] = "date";
That, in and of itself, will bomb your code and MATLAB.
This line will bomb your code if the caller does not request 2 outputs:
plhs[1] = mxCreateDoubleMatrix(1,1,mxREAL);
This line will eventually bomb MATLAB because you can't re-use mxArray pointers (plhs[1]) this way when stuffing them into a cell array or struct array:
mxSetFieldByNumber(plhs[0],i,mva_field,plhs[1]);
You need to create a brand new mxArray for each of these iterative calls, and not re-use plhs[1] over and over. In fact, you should not use plhs[1] here at all ... use a different mxArray pointer. (There is another unofficial way involving bumping up the reference count, but I will not go into that here)
  3 Comments
James Tursa
James Tursa on 23 Jan 2014
Edited: James Tursa on 23 Jan 2014
You only need one mxArray * variable, you just need to create the mxArray that it points to new each iteration. E.g.,
mxArray *mx;
:
LOOP {
mx = mxCreateWhatever(etc);
mxSetFieldByNumber(etc,etc,etc,mx);
}
Note that I have only one pointer variable, mx, but at each iteration it points to a brand new created mxArray.
As for the error you were getting, I could only comment if I saw the code itself (but it sounds like you had a pointer indirection issue).
Finally, no need to apologize. We have all been there and some of this stuff is not well documented (or even documented at all).
abc
abc on 23 Jan 2014
Edited: abc on 23 Jan 2014
@James, Got it! The error was that it was not initialized at the very beginning of the code I feel. Also I then used mxCreateDoubleScalar instead of mxCreateDoubleMatrix and it is running now. There is only a minor modification I need now. The date I get is in chars and so are some other fields. What I want to do from this in MATLAB is to form these fields into vectors. It is fine for the integer fields but for the fields that contain characters, if I read them all in an array, I get all the characters in a string like'5/1/2000 0:00 5/1/2000 0:01' and so on. I am trying to use mxCreateCharMatrixFromStrings in my mex code but it is not running successfully. There is the error of too few arguments to call
Here is the modification I made for that. I know that the problem is in plhs[0], it cannot be accessed like this I feel. But how can I copy it to a different array of strings? mxGetFieldByNumber will get me only one element of that field at a time. Should I then use a for loop to get all elements into an array of strings and then use this function of mxCreateCharMatrixFromStrings?
mxArray *strtmp
strtmp=mxCreateCharMatrixFromStrings((mwSize)count, (const char **) (plhs[0].date));

Sign in to comment.

More Answers (1)

Bruno Pop-Stefanov
Bruno Pop-Stefanov on 22 Jan 2014
My intuition tells me that you get this error when you try to access temp[20]. You allocate an array temp of only 20 char, but you never check that k is less than 20. It's enough to have 20 characters (or more) between two tabs to crash your program.
Allocate a bigger array for temp and add if statements to check that you never go out of bounds when writing into temp and buf.
  1 Comment
abc
abc on 22 Jan 2014
@Bruno, Thank you for your prompt response. I understand what you are saying. I will try making the change you suggested. But I had tested my C code before mexing it and it was running fine. Is it possible that I made a mistake in mexing the file? If it helps I can attach my C code?
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define NAME "Cooley3_dynxfmr_20100501000000_20100930235930.txt"
int main(void)
//int mexFunction(int INPUT, char *NAME)
{
//Structure
typedef struct _col{
char date[20];
float mva;
char qc_load[1];
float air;
char qc_air[1];
float oil;
char qc_oil[1];
float wind_a;
char qc_wind_a[1];
float wind_b;
char qc_wind_b[1];
float wind_c;
char qc_wind_c[1];
float tamb1;
char qc_tamb1[1];
} col;
char buf[1024];
char temp[20];
int count = 0;
int i, j, k, l;
//open file to count elements
int ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start counting no. of elements
while(fgets(buf, sizeof(buf), ptr_file) != NULL)
count++;
fclose(ptr_file);
}
col *elem = malloc(count*sizeof(col));
//open file again for storing elements columnwise
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start collecting data
for(i=0;i<count;i++){ //increment line
//get line
fgets(buf, sizeof(buf), ptr_file);
j=0;
k=0;
//extract first word
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
strcpy(elem[i].date, temp);
//extract second word
k=0;
// strcpy(temp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
elem[i].mva = atof(temp);
//extract third word
k=0;
// strcpy(temp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
strcpy(elem[i].qc_load, temp);
//similarly for all other words
}
fclose(ptr_file);
}
printf("%s\t%f\t%s\t%f\t%f\t%s\n", elem[count-1].date, elem[count-1].mva, elem[count-1].qc_load, elem[count-1].air, elem[count-1].wind_a, elem[count-1].qc_wind_c);
free(elem);
return 0;
}

Sign in to comment.

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!