FilesSearcher 程序 - 程序接收到信号 SIGSEGV,分段错误

FilesSearcher Program - Program received signal SIGSEGV, Segmentation fault

我写了一个简单的程序,可以在文件中搜索特定的文本,但是我得到了这个错误: 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[=11=]", "lol[=11=]", "asd[=11=]", "lmao[=11=]", "rotfl[=11=]"};
    std::vector<std::string> exts = {"txt[=11=]"};

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

};

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

FileContent.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();
};
  1. 您的代码没有像发布的那样编译。
  2. 您正在混合 new[]free()
    使用 -fsanitize=address 构建代码会产生:
==1926539==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs free) on 0x6030000000a0
    #0 0x7f641b887b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
    #1 0x55a4e0211a4a in FilesSearcher::check_file_ext(char const*) FilesSearcher.cc:118
    #2 0x55a4e0210baf in FilesSearcher::parse_files(char const*) FilesSearcher.cc:34
    #3 0x55a4e0216f6a in main test_files_searcher.cc:33
    #4 0x7f641b458d09 in __libc_start_main ../csu/libc-start.c:308
    #5 0x55a4e02104b9 in _start (a.out+0x34b9)

0x6030000000a0 is located 0 bytes inside of 23-byte region [0x6030000000a0,0x6030000000b7)
allocated by thread T0 here:
    #0 0x7f641b8897a7 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
    #1 0x55a4e0211a7b in FilesSearcher::sub_array(char const*, int, int) FilesSearcher.cc:125
    #2 0x55a4e02119bf in FilesSearcher::check_file_ext(char const*) FilesSearcher.cc:111
    #3 0x55a4e0210baf in FilesSearcher::parse_files(char const*) FilesSearcher.cc:34
    #4 0x55a4e0216f6a in main test_files_searcher.cc:33
    #5 0x7f641b458d09 in __libc_start_main ../csu/libc-start.c:308
  1. 将对 free() 的调用替换为 delete[] 后:
==1927190==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000113 at pc 0x7fbe6ef2ad54 bp 0x7ffc8f56c7a0 sp 0x7ffc8f56bf50
READ of size 4 at 0x602000000113 thread T0
    #0 0x7fbe6ef2ad53 in __interceptor_strcasecmp ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:511
    #1 0x562c2ffc8a30 in FilesSearcher::check_file_ext(char const*) FilesSearcher.cc:113
    #2 0x562c2ffc7baf in FilesSearcher::parse_files(char const*) FilesSearcher.cc:34
    #3 0x562c2ffc7be7 in FilesSearcher::parse_files(char const*) FilesSearcher.cc:38
    #4 0x562c2ffc7be7 in FilesSearcher::parse_files(char const*) FilesSearcher.cc:38
    #5 0x562c2ffcdf8c in main test_files_searcher.cc:33
    #6 0x7fbe6eb1bd09 in __libc_start_main ../csu/libc-start.c:308
    #7 0x562c2ffc74b9 in _start (a.out+0x34b9)

0x602000000113 is located 0 bytes to the right of 3-byte region [0x602000000110,0x602000000113)
allocated by thread T0 here:
    #0 0x7fbe6ef4c7a7 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
    #1 0x562c2ffc8a9d in FilesSearcher::sub_array(char const*, int, int) FilesSearcher.cc:125
    #2 0x562c2ffc89d3 in FilesSearcher::check_file_ext(char const*) FilesSearcher.cc:111
    #3 0x562c2ffc7baf in FilesSearcher::parse_files(char const*) FilesSearcher.cc:34
    #4 0x562c2ffc7be7 in FilesSearcher::parse_files(char const*) FilesSearcher.cc:38
    #5 0x562c2ffc7be7 in FilesSearcher::parse_files(char const*) FilesSearcher.cc:38
    #6 0x562c2ffcdf8c in main test_files_searcher.cc:33
    #7 0x7fbe6eb1bd09 in __libc_start_main ../csu/libc-start.c:308

这是因为您没有 NUL-终止您在 sub_array 中创建的字符串。解决这个问题,最终生成一个没有显示 AddressSanitizer 错误并且不会崩溃的程序。

TL;DR:使用 AddressSanitizer。此外,如果您使用 std::string 而不是对 C 风格的字符串进行操作,此程序会更简单。