当我调用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库。
TLDR:我正在使用的书有一个函数a和另一个类似的函数B。我将代码输入到文本编辑器中,并在编辑器中编写函数a的代码。然后我复制粘贴了A,并将其修改为函数B。只是我忘了做一个更改,这就是导致segfault的原因。
我终于明白了为什么我的程序会出错。。。有点事实证明,即使在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_canonialize_dyamic_symtab。在我修改的load_dynsym_bfd版本中,当包含bfd_canonicalize_symtab的行被注释掉时,segfault就消失了。