Ошибка сегментации при вызове std :: make_unique - PullRequest
0 голосов
/ 03 мая 2020

Кажется, я получаю ошибку сегментации, когда звоню std::make_unique<uint8_t []>. Я почти уверен, что знаю, где происходит ошибка сегментации, потому что я использовал gdb; Однако я не могу понять, как это исправить. Вот исходный код с отфильтрованными не относящимися к делу частями.

loader. cc:

#include "loader.h"
... // Other code that would make this post unnecessarily long
Section::Section(Binary& bin, bfd *bfd_h, asection *as) : binary(bin) {
    int bfd_flags = bfd_section_flags(as);
    const char *secname;
    Section::SectionType sectype;

    sectype = Section::SectionType::NONE;
    if (bfd_flags & SEC_CODE) {
        sectype = Section::SectionType::CODE;
    } else if (bfd_flags & SEC_DATA) {
        sectype = Section::SectionType::DATA;
    }

    this->type = sectype;
    this->vma = bfd_section_vma(as);
    this->size = bfd_section_size(as);

    secname = bfd_section_name(as);
    this->name = std::string { secname != nullptr ? secname : "<unnamed>" };

    this->bytes = std::make_unique<uint8_t []>(this->size); // SEGFAULT RIGHT HERE
    if (!bfd_get_section_contents(bfd_h, as, this->bytes.get(), 0, this->size)) {
        throw std::runtime_error("Failed to read section");
    }

}

int Binary::load_binary(std::string& fname) {
    int ret;
    const bfd_arch_info_type *bfd_info;
    std::unique_ptr<bfd, bfd_deleter> bfd_h;

    try {
        bfd_h = open_bfd(fname);
    } catch (bfd_exception& be) {
        std::cerr << be.fname() << ": " << be.what() << " (" << be.errormsg() << ")" << std::endl;
        goto fail;
    }

    this->filename = std::string (fname);
    this->entry = bfd_get_start_address(bfd_h.get());

    this->type_str = std::string (bfd_h->xvec->name);

    switch (bfd_h->xvec->flavour) {
        case bfd_target_elf_flavour:
            this->type = Binary::BinaryType::ELF;
            break;
        case bfd_target_coff_flavour:
            this->type = Binary::BinaryType::PE;
            break;
        case bfd_target_unknown_flavour:
        default:
            std::cerr << "unsupported binary type ("
                  << bfd_h->xvec->name << ")" << std::endl;
            goto fail;
    }

    bfd_info = bfd_get_arch_info(bfd_h.get());
    this->arch_str = std::string{bfd_info->printable_name};

    switch (bfd_info->mach) {
        case bfd_mach_i386_i386:
            this->arch = Binary::BinaryArch::X86;
            this->bits = 32;
            break;
        case bfd_mach_x86_64:
            this->arch = Binary::BinaryArch::X86;
            this->bits = 64;
            break;
        default:
            std::cerr << "unsupported architecture (" << bfd_info->printable_name·
                      << bfd_info->printable_name << ")" << std::endl;
            goto fail;
    }

    this->load_symbols(bfd_h.get());
    this->load_dynsym(bfd_h.get());

    if (this->load_sections(bfd_h.get()) < 0) goto fail;

    ret = 0;
    goto success;

    fail:
        ret = -1;

    success:
        return ret;
}

... // Other code that would make this post unnecessarily long

loader.h:

#include <memory>
#include <vector>
#include <bfd.h>
#include <inttype.h>
... // Other code that would make this post unnecessarily long
class Section {
    public:
        enum class SectionType { NONE, CODE, DATA };
        Section(Binary& bin);
        Section(Binary& bin, bfd *bfd_h, asection *as);
        bool contains(uint64_t addr);
        void info();

    private:
        friend class Binary;
        Binary& binary;
        std::string name;
        SectionType type;
        uint64_t vma;
        uint64_t size;
        std::unique_ptr<uint8_t []> bytes;

};

class Binary {
    public:
        enum class BinaryType { AUTO, ELF, PE };
        enum class BinaryArch { NONE, X86 };

        Binary();
        Section* get_section_text();
        int load_binary(std::string &fname);
        void info();

    private:
        std::string filename;
        BinaryType type;
        std::string type_str;
        BinaryArch arch;
        std::string arch_str;
        unsigned bits;
        uint64_t entry;
        std::vector<Section> sections;
        std::vector<Symbol> symbols;

        int load_symbols(bfd *bfd_h);
        int load_dynsym(bfd *bfd_h);
        int load_sections(bfd *bfd_h);
... // Other code that would make this post unnecessarily long
};

Вот обратный след, который GDB вернул:

(gdb) bt
#0  0x00007fffff335b9f in unlink_chunk (p=p@entry=0x802b7d0, av=0x7fffff46cb80 <main_arena>) at malloc.c:1453
#1  0x00007fffff338881 in _int_malloc (av=av@entry=0x7fffff46cb80 <main_arena>, bytes=bytes@entry=36) at malloc.c:4041        #2  0x00007fffff339a84 in __GI___libc_malloc (bytes=36) at malloc.c:3058
#3  0x00007fffff546045 in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x0000000008003b94 in std::make_unique<unsigned char []> (__num=36) at /usr/include/c++/10/bits/unique_ptr.h:966
#5  Section::Section (this=0x7ffffffedd80, bin=..., bfd_h=0x801b730, as=0x801dbf8) at loader.cc:66
#6  0x0000000008003d53 in Binary::load_sections (this=this@entry=0x7ffffffedec0, bfd_h=bfd_h@entry=0x801b730)
    at loader.cc:122
#7  0x000000000800487e in Binary::load_binary (this=0x7ffffffedec0, fname=...) at loader.cc:185
#8  0x0000000008002451 in main (argc=<optimized out>, argv=<optimized out>) at loader_demo.cc:13

Этот код основан на коде из "Практического двоичного анализа", так что извините за переход. Я также использую библиотеку bfd.

1 Ответ

0 голосов
/ 04 мая 2020

TLDR : книга, которую я использовал, имела функцию A и другую функцию B, которая была похожа на нее. Я ввел код в свой текстовый редактор и написал код для функции A в моем редакторе. Затем я скопировал и вставил A и изменил его в функцию B. За исключением того, что я забыл внести одно изменение, и это было причиной ошибки.

Я наконец-то узнал, почему моя программа была segfaulting ... вроде. Оказывается, в любом коде не было ничего плохого даже рядом с make_unique; Тем не менее, я подумал, что это так, поскольку трассировка стека в выводе GDB указала, что ошибка была в make_unique.

Ошибка фактически была при копировании кода. В книге был фрагмент кода функции load_symbols_bfd. Я набрал код в своем текстовом редакторе и изменил код на более современный C ++. Была похожая функция с именем load_dynsym_bfd. Я решил, что могу скопировать измененную версию load_symbols_bfd и изменить ее на свою собственную версию load_dynsym_bfd. Однако я забыл изменить одно из имен функций в моей модифицированной версии load_dynsym_bfd, которая была в load_symbols_bfd; Я забыл изменить bfd_canonicalize_symtab на bfd_canonicalize_dynamic_symtab. Когда строка, содержащая bfd_canonicalize_symtab, была закомментирована в моей модифицированной версии load_dynsym_bfd, ошибка исчезла.

...