简体   繁体   中英

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;}
  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.

I would like to extend on @phoxis answer:

If you can reliably reproduce the error running the program under GDB and evaluating the stack is probably easiest.

Sometimes however, the bug might only manifest under certain circumstances or even worse you have a race condition in a multithreaded program and the segfault only happens once in a dozen runs.

This is why I would generally recommend to enable core dumps for your development and testing machines. In this case the kernel will write a dump of your program from the moment it tried to access memory it was not allowed to do. The good thing now is that you can load this core with GDB, eg:

gdb -c <your-core-file>

You then can get the stacktrace of what happened with

> bt

Or in case of a multi threaded program you can get stack traces for all threads with:

> thread apply all bt

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM