Ptru Ptru - 2 months ago 12
C++ Question

How to debug segmentation fault in c++ when everything compiles correctly?

So I've written a script for an assignment that does some matrix calculations. The input data consist of A(N x N), B(N x M) and pi(1 x N) matrices. All the testcases I am given give the correct results when the script is run. However when going though the assignment checker it gives me the following error:


Signal 11 is SIGSEGV, Segmentation Violation. This means that your
program has tried to access memory which it was not allowed to access,
either because the memory was not mapped by the process or due to
permission errors. Make sure everything is properly initialized, be
careful with your pointer arithmetic and don't follow null pointers.


I also googled (http://www.cyberciti.biz/tips/segmentation-fault-on-linux-unix.html), which told me that this error usually occur when i try to access memory which is not allowed. I however don't think this is the case here because i have all the calculations inside if-statements that check if the dimensions are faulty.

Does anyone know what this kind of error means, how to debug this kind of problems, and how to check against this? It's really hard to find since it compiles correctly and the calculations against the check cases are correct.

#include <iostream>
#include <fstream> // fstream
#include <sstream> // stringstream

using namespace std;

double **matCalc(double **A, double **B, int m, int n, int p, int q);

int main(){
std::istream &infile = std::cin;
if(infile){

std::string A_str;
std::string B_str;
std::string pi_str;

getline(infile, A_str);
getline(infile, B_str);
getline(infile, pi_str);

std::stringstream A_obj(A_str);
std::stringstream B_obj(B_str);
std::stringstream pi_obj(pi_str);

int m,n; // A
int p,q; // B
int r,s; // pi
int i,j,t; // iterators

A_obj >> m >> n;
B_obj >> p >> q;
pi_obj >> r >> s;


// Fill A
double **A = new double *[m];
for (i = 0; i < m; ++i){
A[i] = new double[n];
}
for (i = 0; i < m; ++i){
for (j = 0; j < n; ++j){
A_obj >> A[i][j];
}

}

// Fill B
double **B = new double *[p];
for (i = 0; i < p; ++i){
B[i] = new double[q];
}
for (i = 0; i < p; ++i){
for (j = 0; j < q; ++j){
B_obj >> B[i][j];
}
}

// Fill pi
double **pi = new double *[r];
for (i = 0; i < s; ++i){
pi[i] = new double[s];
}
for (i = 0; i < r; ++i){
for (j = 0; j < s; ++j){
pi_obj >> pi[i][j];
}
}

if (s == m){
double **CE = matCalc(pi, A, r, s, m, n);
int CE_row = r;
int CE_col = n;
if (CE_col == p){
double **EPD = matCalc(CE, B, CE_row, CE_col, p, q);
int EPD_row = CE_row;
int EPD_col = q;

cout << EPD_row << " " << EPD_col << " ";
for (i = 0; i < EPD_row; ++i){
for(j = 0; j < EPD_col; ++j){
cout << EPD[i][j] << " ";
}
}
}
else{cout << "Dim. Error" << endl;}
}
else{cout << "Dim. Error" << endl;}
}
return 0;
}


double **matCalc(double **A, double **B, int m, int n, int p, int q){
if (n==p){
int i,j,k;
double **c = new double *[m];
for (i = 0; i < m; ++i){
c[i] = new double[q];
}


for (i = 0;i < m; ++i){

for (j = 0;j < q; ++j){
c[i][j] = 0;
for (k = 0; k < n; ++k){
c[i][j] = c[i][j] + (A[i][k] * B[k][j]);
}
}
}
return c;
}
else{
double **c = 0;
cout << "Dim. Error" << endl;
return c;
}
//return c;
}


In particular - This section writes the answer which is checked against.

if (s == m){
double **CE = matCalc(pi, A, r, s, m, n);
int CE_row = r;
int CE_col = n;
if (CE_col == p){
double **EPD = matCalc(CE, B, CE_row, CE_col, p, q);
int EPD_row = CE_row;
int EPD_col = q;

cout << EPD_row << " " << EPD_col << " ";
for (i = 0; i < EPD_row; ++i){
for(j = 0; j < EPD_col; ++j){
cout << EPD[i][j] << " ";
}
}
}
else{cout << "Dim. Error" << endl;}
}
else{cout << "Dim. Error" << endl;}

Answer
  double **pi = new double *[r];
        for (i = 0; i < s; ++i){
            pi[i] = new double[s];
        }
  • Here you have allocated r double *s but iterated over i=0;i<s . This can be a potential problem. Therefore, carefully check variable ranges, lifetime of allocated memory.

  • Also, in double **EPD = matCalc(CE, B, CE_row, CE_col, p, q); CE, can be NULL from the previously returned value from matCalc call. There is no check if the return value was NULL OR, you do not have any check for illegal pointer dereferences within the function matCalc, which I will highly recommend.

  • Also, instead of passing pointer to a pointer, you might want to wrap the matrix into a class (or a struct), and define operations, like allocate and free. Possibly use smart pointers and stay safe.

  • In general, you can use debugger, like gdb and valgrind

  • Also, even it compiles properly, use the -Wall or both the -Wall -Wextra to see the warnings.