尝试读取/写入Graphviz DAG值的工作证明会导致段错误

时间:2018-07-18 02:51:25

标签: c++ linux graphviz directed-acyclic-graphs

更新:在使用-g进行编译并检查了有问题的每一行之后,它现在已经设法在系统级头文件中进行段错误:

Program received signal SIGSEGV, Segmentation fault.
__gnu_cxx::new_allocator<char*>::construct<char*, char* const&> (this=0x7fffffffdec0, 
__p=0x5555557702f0, __args#0=<error reading variable>)
at /usr/include/c++/8.1.1/ext/new_allocator.h:136
136             { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

这是我以前从未见过的东西。

因此,我有一个非常简单的C ++程序,至少要尝试同时写入文件和从文件中读取文件,以确保DA​​G中绝对没有重复值(变量名更改为保护个人商业秘密):

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>

struct parsedline {
    unsigned long long pre_edge;
    unsigned long long post_edge;
};

std::vector<parsedline> readfile(std::string name) {
    //create array of parsedlines for later use
    std::vector<parsedline> edges;

    //count lines and create array of lines
    int linecount = 0;
    std::vector<char*> lines;
    std::ifstream dag(name);
    std::string ul;

    while (std::getline(dag, ul)) {

        //convert to c_str immediately to avoid errors with atoi
        std::istringstream thisline;
        thisline.str(ul);
        lines[linecount] = const_cast<char*>(thisline.str().c_str());
        ++linecount;

    }

    //drop block definition in graphviz file representing DAG
    int max_readable_line = sizeof(lines) - 2;
    std::vector<char*> readable_lines;

    for (int i = 0; i < max_readable_line; i++) {

        //shift index to skip line 1
        int rlindex = i+1;
        readable_lines[i] = lines[rlindex];

    }

    //read integers from each line, store them in array of parsedline objects
    for (int j = 0; j < max_readable_line; j++) {

        int edge_begin, edge_end;
        if (std::sscanf(readable_lines[j], "   %d -> %d", &edge_begin, &edge_end)) {
            edges[j].pre_edge = edge_begin;
            edges[j].post_edge = edge_end;
        }

    }
    return edges;
}

int main (int argc, char **argv) {

    unsigned long long minperrank = atoi(argv[1]);
    unsigned long long maxperrank = atoi(argv[2]);
    unsigned long long minranks = atoi(argv[3]);
    unsigned long long maxranks = atoi(argv[4]);
    double edgechance = atof(argv[5]);
    std::string filedest(argv[6]);

    unsigned long long i,j,k,l,nodes = 0;
    std::srand(time(NULL));

    unsigned long long ranks = minranks + (std::rand() % (maxranks - minranks + 1));

    std::ofstream dagout(filedest, std::ofstream::out);
    std::vector<parsedline> lines = readfile(filedest);

    dagout << "digraph {" << std::endl;

    for(i = 0; i < ranks; i++) {
        unsigned long long newnodes = minperrank + (rand() % (maxperrank - minperrank + 1));

        for (j = 0; j < nodes; j++) {

            for (k = 0; k < newnodes; k++) {

                unsigned long long checkval = std::rand() % 100;

                if (checkval < edgechance) {

                    for (l = 0; l < sizeof(lines); l++) {

                        //each new member must be a nonce
                        unsigned long long pree = lines[l].pre_edge;
                        unsigned long long poste = lines[l].post_edge;
                        if (checkval != pree) {

                            if (checkval != poste) {

                                dagout << "   " << j << " -> " << k+nodes << ";" << std::endl;

                            }

                        }

                    }

                }

            }

        }

        nodes += newnodes;

    }

    dagout << "}" << std::endl;
    return 0;
}

这可以正常编译,但是当我尝试运行它时:

[realkstrawn93@archlinux Desktop]$ ./gendag 10 10 10 10 0.1 test.gv
Segmentation fault (core dumped)
[realkstrawn93@archlinux Desktop]$ 

这是gdb的输出-它表示它在readfile函数中,但没有确切说明它在该函数中的位置:

[realkstrawn93@archlinux Desktop]$ gdb gendag
GNU gdb (GDB) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gendag...(no debugging symbols found)...done.
(gdb) r 10 10 10 10 0.1 test.gv
Starting program: /home/realkstrawn93/Desktop/gendag 10 10 10 10 0.1 test.gv

Program received signal SIGSEGV, Segmentation fault.
0x0000555555555675 in readfile(std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >) ()

我需要知道段错误在该函数中的确切位置。

2 个答案:

答案 0 :(得分:1)

//count lines and create array of lines
int linecount = 0;
std::vector<char*> lines;  <--
std::ifstream dag(name);
std::string ul;

while (std::getline(dag, ul)) {

    //convert to c_str immediately to avoid errors with atoi
    std::istringstream thisline;
    thisline.str(ul);
    lines[linecount] = const_cast<char*>(thisline.str().c_str()); <--
    ++linecount;

}

您正在初始化lines[linecount]之前对其进行访问。尽管向量已初始化为空,但其元素未初始化。使用

lines.push_back(const_cast<char*>(thisline.str().c_str()));

代替访问运算符([])(如果您所需要做的只是在向量的末尾附加一个元素)。

否则,如果必须按元素的位置访问元素,则首先通过将参数传递给构造函数(如inp)进行初始化

std::vector<char*> lines(max_lines);

这将初始化向量以包含max_lines个空对象。

当程序访问不属于它的内存时,就会发生分段错误。由于向量总是分配在堆上,因此访问超出其范围的任何数据都将导致段错误。

答案 1 :(得分:0)

事实证明,我必须在继续操作之前检查数组的大小是否为0。否则,它是一个空指针取消引用:

if (lines.size() == 0) {

    dagout << "   " << j << " -> " << k+nodes << ";" << std::endl;

} else {

    //each new member must be a nonce
    unsigned long long pree = lines.at(l).pre_edge;
    unsigned long long poste = lines.at(l).post_edge;
    if (std::rand() % 100 != pree) {

        if (std::rand() % 100 != poste) {

            dagout << "   " << j << " -> " << k+nodes << ";" << std::endl;

        }

    }

}

但是,现在,我遇到了一个无限循环问题-那是一个完全不相关的问题,我可以自己解决。