Попытка при доказательстве работы чтения / записи значений Graphviz DAG вызывает segfault

Обновить: После компиляции с помощью -g и проверки каждой проблемной строки теперь он может выполнить segfault в заголовочном файле системного уровня:

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 ++, которая, по крайней мере, пытается писать и читать из файла одновременно, чтобы убедиться, что в DAG вообще нет повторяющихся значений (имена переменных изменены для защиты личной торговли). секреты):

#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> >) ()

Мне нужно знать, где именно в этой функции Segfault.

0

Решение

//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()));

вместо оператора доступа ([]) если все, что вам нужно, это добавить элемент в конец вектора.

В противном случае, если вам необходимо получить доступ к элементам по их позиции, сначала инициализируйте их, передав аргумент конструктору, как в

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

который инициализирует вектор для содержания max_lines пустые предметы.

Ошибка сегментации происходит, когда ваша программа обращается к памяти, которая ей не принадлежит. Поскольку векторы всегда размещаются в куче, доступ к любым данным после их окончания приведет к segfault.

1

Другие решения

Оказывается, мне пришлось проверить, равен ли размер массива 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;

}

}

}

Однако теперь у меня возникла проблема с бесконечным циклом — это совершенно не связанная проблема, которую я могу решить самостоятельно.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector