c++ - 调用 std::make_unique 时出现分段错误
问题描述
我打电话时似乎遇到了分段错误std::make_unique<uint8_t []>
。我很确定我知道分段错误发生在哪里,因为我使用了 gdb;但是,我不知道如何解决它。这是过滤掉不相关部分的源代码。
加载器.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
装载机.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
此代码基于“实用二进制分析”中的代码,因此请原谅 goto。我也在使用 bfd 库。
解决方案
TLDR:我使用的这本书有一个函数 A 和另一个与之相似的函数 B。我将代码输入到我的文本编辑器中,并在我的编辑器中编写了函数 A 的代码。然后我复制并粘贴 A 并将其修改为函数 B。除了我忘记进行一项更改,这就是导致段错误的原因。
我终于发现了为什么我的程序会出现段错误……有点。事实证明,即使在 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 修改版本中被注释掉时,段错误消失了。
推荐阅读
- docker - 在 docker 中映射用户的跨操作系统兼容方式
- python - Plotly/Dash 日期时间图
- puppet - puppet/hiera : 在 puppet 应用期间找不到模块类
- java - 当任何 PIT 突变失败而不是突变覆盖率时,maven build 可能会失败?
- python - 未按预期将带有数组的嵌套 ctypes 结构传递给 C 库函数
- html - 仅悬停在父菜单项上时强制显示子菜单
- python - 匹配 ID 中多个列的值
- android - Firebase-perf 与 let 插件冲突
- android - React-native 应用程序在真正的 android 设备上崩溃
- vb.net - vb.net winforms datetimepicker - 更改禁用日期的字体颜色