Bizarre SegFault

Well, this one has me stumped- I have code that... well, works. Other than some segfault. Using Code::Blocks, I managed to determine that the segfault happens when a constructor for the class Matrix is called.

Except in no case of the function set_matrix is that constructor called.

Worse yet, the segfault happens upon the exit of the constructor- the rest of it works fine. I honestly have no idea what is going on here. The issue is when I call graph.set_matrix(Matrix). The odd part is, the constructor where the segfault is happening (in the constructor for Matrix when passed another Matrix object) doesn't cause a segfault in normal applications- hell, it works fine. So the constructor isn't the issue. Only the function call causes the fault- and I can't discern why the function is even calling the constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef GRAPH_H
#define GRAPH_H
#include <iostream>
#include <fstream>
#include "Matrix.h"

using std::vector;


class Graph
{
public:
    Graph();
    ~Graph();
    void set_matrix(Matrix& matrix) {base_matrix = matrix;}
    void set_monoid() {monoid_matrix = base_matrix.laplacian2();}
    void fetch_matrix(std::string);
protected:
private:
    vector<Matrix> monoid_set;
    Matrix base_matrix;
    Matrix monoid_matrix;

    vector<Matrix> create_monoid_vector();
};

#endif // GRAPH_H 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
#include <algorithm>

using std::vector;

struct Matrix
{
public:
    Matrix();
    Matrix(vector<vector<int>>&);
    Matrix(const Matrix&);
    Matrix operator * (const Matrix&);
    Matrix operator = (const Matrix&);
    Matrix operator *= (const Matrix&);
    bool operator == (const Matrix&);
    bool operator != (const Matrix&);
    Matrix laplacian2 ();
    vector<vector<int>> matrix;
};

#endif // MATRIX_H 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "Matrix.h"

Matrix::Matrix()
{

}

Matrix::Matrix(vector<vector<int>> &rhs)
{
    vector<int> placeholder;
    placeholder.resize(rhs.begin()->size());
    this->matrix.resize(rhs.size());
    auto i = this->matrix.begin();
    for(auto j = rhs.begin(); j != rhs.end(); ++i, ++j)
    {
        *i = *j;
    }
}

Matrix::Matrix(const Matrix& other)                                     //Ghost constructor
{
    vector<int> placeholder;
    placeholder.resize(other.matrix.begin()->size());
    this->matrix.resize(other.matrix.size(),placeholder);
    auto i = this->matrix.begin();
    for(auto j = other.matrix.begin(); j != other.matrix.end(); ++i, ++j)
    {
        *i = *j;
    }
}
Matrix Matrix::operator * (const Matrix& rhs)
{
    if(this->matrix.begin()->size() != rhs.matrix.size())
    {
        Matrix error;
        return error;
    }

    Matrix return_matrix;
    vector<int> internal_matrix;
    internal_matrix.resize(this->matrix.begin()->size());
    return_matrix.matrix.resize(rhs.matrix.size(),internal_matrix);
    for(int i = 0; i <= this->matrix.size(); ++i)
    {
        for(int j = 0; j <= rhs.matrix[i].size(); ++j)
        {
            int insertion_value = 0;
            for(int k = 0; k <= this->matrix[i].size(); ++k)
            {
                insertion_value += (this->matrix[i][k] * rhs.matrix[k][j]);
            }
            return_matrix.matrix[i][j] = insertion_value % 2;
        }
    }
    return return_matrix;
}

Matrix Matrix::operator = (const Matrix& rhs)
{
    auto i = this->matrix.begin();
    for(auto j = rhs.matrix.begin(); j != rhs.matrix.end(); ++i, ++j)
    {
        *i = *j;
    }
    return *this;
}

Matrix Matrix::operator *= (const Matrix& rhs)
{
    *this = *this * rhs;
    return *this;
}

bool Matrix::operator == (const Matrix& rhs)
{
    if((this->matrix.size() != rhs.matrix.size())||(this->matrix.begin()->size() != rhs.matrix.begin()->size()))
        return false;
    for(int i = 0; i <= this->matrix.size(); ++i)
        for(int j = 0; j <= this->matrix[i].size(); ++j)
            if(this->matrix[i][j] != rhs.matrix[i][j])
                return false;
    return true;
}

bool Matrix::operator != (const Matrix& rhs)
{
    if((this->matrix.size() != rhs.matrix.size())||(this->matrix.begin()->size() != rhs.matrix.begin()->size()))
        return true;
    for(int i = 0; i <= this->matrix.size(); ++i)
        for(int j = 0; j <= this->matrix[i].size(); ++j)
            if(this->matrix[i][j] != rhs.matrix[i][j])
                return true;
    return false;
}

Matrix Matrix::laplacian2()
{
    int placement = 0;
    for(auto i : this->matrix)
    {
        int running_sum = 0;
        for(auto j : i)
            running_sum += j;
        if (running_sum % 2)
            this->matrix[placement][placement] = 1;
        ++placement;
    }
    return *this;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "Graph.h"

int main()
{
    Graph graph;
    vector<vector<int>> input;
    input.emplace_back((0,1,1));
    input.emplace_back((1,0,1));
    input.emplace_back((1,1,0));
    Matrix matrix(input);
    Matrix matrix2(matrix);   //Calls the same constructor, but no segfault!
    graph.set_matrix(matrix); //Segfault!
    return 0;
}


Last edited on
Your definitions are incomplete, you are missing default constructor, destructor and fetch_matrix definitions. Post cpp file gor Graph too.


Last edited on
It doesn't really have to do with the issue as far as I can tell, but sure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "Graph.h"

Graph::Graph()
{
    //ctor
}

Graph::~Graph()
{
    //dtor
}

vector<Matrix> Graph::create_monoid_vector()    //fills the monoid vector with a to a^n, where a^(n+1) = a^k for some k
{
    vector<Matrix> return_set;
    Matrix copy_matrix = monoid_matrix;
    bool is_looped = false;
    do
    {
        return_set.emplace_back(copy_matrix);
        copy_matrix *= monoid_matrix;
        for(auto& i : return_set)
            if(i == copy_matrix)
            {
                is_looped = true;
                break;
            }

    } while(!is_looped);
}


Yes, fetch_matrix has no implementation yet. The hope is to be able to pass to it a file location for a text document so you can import a matrix.
1
2
3
4
5
6
7
8
9
Matrix Matrix::operator = (const Matrix& rhs)
{
    auto i = this->matrix.begin();
    for(auto j = rhs.matrix.begin(); j != rhs.matrix.end(); ++i, ++j)
    {
        *i = *j;
    }
    return *this;
}
Guess what happens if this->matrix is empty or have less elements than rhs? I'll give a hint: It starts with "access"and ends with "out of bounds".

And learn how to use a debugger:
1
2
3
4
5
#0 004046BC	std::vector<int, std::allocator<int> >::capacity(this=0x0)
#1 00406EB6	std::vector<int, std::allocator<int> >::operator=(this=0x0, __x=...) 
#2 00401AAC	Matrix::operator=(this=0x22fd98, rhs=...) //<problem is here
#3 00403A1B	Graph::set_matrix(this=0x22fd80, matrix=...)
#4 004020B0	main() 

Last edited on
Thanks for being rude, but the problem is resolved- I'm just going to install an external library that would do a better job.

And I know how to use a debugger. It hit the segfault at the end of the constructor- it never reached the assignment operand. Sorry that I haven't been doing this for 20 years and know the ins and outs of every single debugger. No need to be so rude about it.
Last edited on
Using the power invested into my debugger, I bestow upon you the line number 63 of the third code section above. That's what's causing your segfault. A bit short on time though so haven't looked at why. I'll leave that to you. ;)
Sorry if my post was rude, I didn't want to offend you, but it looks I wasn't succesfull.

It hit the segfault at the end of the constructor- it never reached the assignment operand.
Do you have optimizations turned on? Optimizations and debugging do not work well together. And what stack trace of your debugger showed you?

I'm just going to install an external library that would do a better job.
It is almost always better to use already existing tested, feature-full library than writing your own.

When doing by-element copy, it is good idea to make sure that destination has sufficient size or change your approach so its size would not matter.
Yeah, I realized that for what I'm doing, there are already much better libraries out there. Eigen, for instance, has the exact thing I was looking for- the ability to create a matrix where the dimensions aren't known on compile time, but can be set when created. Sure, I could just dynamically allocate, but that tends to be much sloppier. So, I'll be sticking with Eigen for the matrix stuff- hopefully they include things such as kernels and dimensions of said kernels.
Topic archived. No new replies allowed.