【发布时间】:2021-08-28 17:39:23
【问题描述】:
我编写了一个简单的程序,它在文件中搜索特定文本,但出现此错误:
Program received signal SIGSEGV, Segmentation fault.
你能告诉我我哪里错了吗,你能告诉我如何使用 GDB 调试器来获取有关我得到的错误的信息吗?
(使用 GDB 我得到这个错误:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555557612 in std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::size() const ()
但我不知道如何获得有关该错误的更多信息,请您解释一下吗?
代码测试程序:
/**
COMPILATION:
g++ test_files_searcher.cpp -o files_searcher.out FilesSearcher_Linux/FilesSearcher.cpp FilesSearcher_Linux/FileContent.cpp
**/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <vector>
#include "FilesSearcher_Linux/FilesSearcher.h"
#define SIZE_SEARCH_MATRIX 0x6
#define SIZE_EXTS_ARRAY 0x1
int main(){
using namespace std;
std::vector<std::string> matrix = {"test\0", "lol\0", "asd\0", "lmao\0", "rotfl\0"};
std::vector<std::string> exts = {"txt\0"};
FilesSearcher fs = FilesSearcher(matrix, exts);
const char *home_path = fs.get_home_path();
cout << "[+] Home Path: " << home_path << endl;
fs.parse_files(home_path);
if(fs.get_found_files().size() > 0x0){
for(FileContent *fc : fs.get_found_files()){
std::cout << "file path == " << fc->get_path() << " file content == " << fc->get_content() << std::endl;
delete fc;
}
}
}
FilesSearcher.cpp:
#include "FilesSearcher.h"
FilesSearcher::FilesSearcher(std::vector<std::string> keywords, std::vector<std::string> extensions){
mKeywords = keywords;
mExtensions = extensions;
}
std::vector<FileContent*> &FilesSearcher::get_found_files(){
return mFoundFiles;
}
const char * FilesSearcher::get_home_path(){
const char *home = std::getenv(ENV_HOME);
if(home == NULL){
struct passwd *pw = getpwuid(getuid());
home = pw->pw_dir;
}
return home;
}
void FilesSearcher::parse_files(const char *base_path){
struct dirent *entry;
DIR *dir = opendir(base_path);
if(dir == NULL){
return;
}
int i = 0x0;
while((entry = readdir(dir)) != NULL){
if(strcmp(PATH_THIS, entry->d_name) != 0x0 && strcmp(PATH_PARENT, entry->d_name) != 0x0){
char *path = format_filepath(base_path, {entry->d_name});
int type = is_regular_file_or_dir(path);
if(type == IS_REGULAR_FILE){
if(check_file_ext(path)){
search_file_content((const char *) path);
}
} else {
parse_files((const char*) path);
}
free(path);
}
}
closedir(dir);
}
void FilesSearcher::search_file_content(const char *file_path){
std::string line;
std::ifstream file(file_path);
if(file.is_open()){
bool add = false;
file.seekg(0x0, std::ios_base::end);
int f_size = file.tellg();
file.seekg(0x0);
char content[f_size];
while(getline(file, line)){
for(int i = 0x0; i < mKeywords.size(); i++){
if(line.find(mKeywords[i]) != std::string::npos){
add = true;
}
}
strcat(content, line.c_str());
}
file.close();
if(add){
FileContent *fc = new FileContent((char *) file_path, get_file_ext(get_last_relative_path(file_path)), content, f_size);
mFoundFiles.push_back(fc);
}
}
}
int FilesSearcher::is_regular_file_or_dir(const char *path){
struct stat path_stat;
if(stat(path, &path_stat) != 0x0){
return 0x0;
}
return S_ISREG(path_stat.st_mode) == 0x1 ? IS_REGULAR_FILE :
S_ISDIR(path_stat.st_mode) == 0x1 ? IS_DIRECTORY : 0x0;
}
char *FilesSearcher::format_filepath(const char *base_path, const std::initializer_list<char *> &args){
char *path = new char[300];
strcpy(path, base_path);
for(char *p: args){
if(path[strlen(path) - 0x1] != '/' && p[0x0] != '/'){
char c = '/';
strncat(path, &c, 0x1);
} else if(path[strlen(path) - 0x1] == '/' && p[0x0] == '/'){
char *temp = sub_array(p, 0x1, strlen(p));
strcpy(p, temp);
free(temp);
}
strcat(path, p);
}
return path;
}
char *FilesSearcher::get_file_ext(const char *file_path){
return strrchr((char*) file_path, '.');
}
char *FilesSearcher::get_last_relative_path(const char *file_path){
return strrchr((char *) file_path, '/');
}
bool FilesSearcher::check_file_ext(const char *file_path){
char *rel = get_last_relative_path(file_path);
if(rel != NULL){
char *ext = get_file_ext(rel);
if(ext != NULL){
ext = sub_array((const char *) ext, 0x1, strlen(ext));
for(int i = 0x0; i < mExtensions.size(); i++){
if(strcasecmp(ext, mExtensions.at(i).c_str()) == 0x0){
free(ext);
return true;
}
}
free(ext);
}
}
return false;
}
char * FilesSearcher::sub_array(const char *arr, int start, int end){
char *ret = new char[end - start];
int index = 0x0;
for(int i = start; i < end; i++){
ret[index] = arr[i];
index++;
}
return ret;
}
FilesSearcher.h:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <vector>
#include "FileContent.h"
#define ENV_HOME "HOME"
#define LINUX_BASE_DIR_PATH "/"
#define IS_REGULAR_FILE 0x1
#define IS_DIRECTORY 0x2
#define PATH_THIS "."
#define PATH_PARENT ".."
class FilesSearcher {
public:
FilesSearcher(std::vector<std::string> keywords, std::vector<std::string> extensions);
const char * get_home_path();
void parse_files(const char *base_path);
std::vector<FileContent*> &get_found_files();
private:
std::vector<std::string> mKeywords;
std::vector<std::string> mExtensions;
std::vector<FileContent*> mFoundFiles;
void search_file_content(const char *file_path);
int is_regular_file_or_dir(const char *path);
char *format_filepath(const char *base, const std::initializer_list<char *> &rel);
char *get_file_ext(const char *file_path);
char *get_last_relative_path(const char *file_path);
bool check_file_ext(const char *file_path);
char *sub_array(const char* arr, int start, int end);
void print_dir_entry_info(dirent *entry, int num_entry);
};
文件内容.cpp:
#include "FileContent.h"
FileContent::FileContent(char *path, char *ext, char *content, int size){
mPath = new char[1000];
strcpy(mPath, path);
mExt = ext;
mContent = new char[size];
strcpy(mContent, content);
mSize = size;
}
FileContent::~FileContent(){
delete mPath;
delete mContent;
}
char *FileContent::get_path(){
return mPath;
}
char *FileContent::get_ext(){
return mExt;
}
char *FileContent::get_content(){
return mContent;
}
int FileContent::get_size(){
return mSize;
}
文件内容.h:
#include <stdio.h>
#include <string.h>
class FileContent {
private:
char *mPath;
char *mExt;
char *mContent;
int mSize;
public:
FileContent(char *path, char *ext, char *content, int size);
~FileContent();
char *get_path();
char *get_ext();
char *get_content();
int get_size();
};
【问题讨论】:
-
快速浏览一下,我发现
FilesSearcher::sub_array没有 nul 终止它的字符串,这是一个问题。还有很多内存泄漏。 -
@1201ProgramAlarm 谢谢您的回答,您能否更好地解释一下我需要在哪里终止字符串以及您看到的内存泄漏?谢谢(:
-
从长远来看,真正有助于您稳定的方法是将所有字符串放入 std::string 中。您也可以从外部函数返回的 char* 构造这些。例如。替换 void parse_files(const char *base_path);使用 parse_files(const std::string& base_path)。该引用确保不会复制 std::string,因此不会很慢。
-
您的代码无法编译(未声明测试程序中使用的
get_home_path())。它也远非最小:stackoverflow.com/help/mcve -
下一步应该是确定代码的哪一行触发了错误,以及此时变量的值是什么。使用 gdb 在崩溃时获取调用堆栈,然后逐步向下直到找到列出的函数之一。这应该让您了解可以为minimal reproducible example 删除代码的哪些部分。您需要搜索所有文件,还是只搜索崩溃时正在处理的一个文件?或者您甚至没有进行处理?也许您可以摆脱
FilesSearcher::parse_files()的声明、定义和调用?