如何在 gdb 中中断 UBSan 报告并继续?

2023-12-20

GCC 和 Clang 的最新版本具有未定义行为清理程序 (UBSan),它是一个编译标志 (-fsanitize=undefined)添加运行时检测代码。出现错误时,会显示如下警告:

packet-ber.c:1917:23: 运行时错误: 54645397829836991 左移 8 位不能用“long int”类型表示

现在我想对此进行调试并在该行上获得调试中断。对于地址消毒器(ASAN)有ASAN_OPTIONS=abort_on_error=1这会导致可捕获的致命错误。唯一可用的 UBSan 选项是UBSAN_OPTIONS=print_stacktrace=1 https://www.chromium.org/developers/testing/undefinedbehaviorsanitizer这会导致报告的调用跟踪转储。然而,这不允许我检查局部变量然后继续程序。用于-fsanitize-undefined-trap-on-error因此不可能。

我应该如何在 UBSan 报告中中断 gdb?尽管break __sanitizer::SharedPrintfCode似乎有效,这个名字看起来很内在。


在破坏检测功能的同时(如@马克·普洛特尼克 https://stackoverflow.com/questions/30809022/how-can-i-break-on-ubsan-reports-in-gdb-and-continue#comment49749394_30809022 and @Iwillnotexist Idonotexist https://stackoverflow.com/a/31459198/427545)是一种选择,更好的方法是破坏检测后报告这些问题的功能。这种方法也适用于 ASAN,其中人们会中断__asan_report_error.

摘要:您可以通过断点停止 ubsan 报告__ubsan::ScopedReport::~ScopedReport or __ubsan::Diag::~Diag。这些是私有的实现细节,但将来可能会发生变化。使用 GCC 4.9、5.1.0、5.2.0 和 Clang 3.3、3.4、3.6.2 进行测试。

对于 GCC 4.9.2 从ppa:ubuntu-工具链-r/测试 https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test?field.series_filter=trusty, 你需要libubsan0-dbg使上述断点可用。 Ubuntu 14.04 与 Clang 3.3 和 3.4 不支持__ubsan::ScopedReport::~ScopedReport断点,因此您只能在打印消息之前中断__ubsan::Diag::~Diag https://github.com/llvm-mirror/compiler-rt/blob/release_34/lib/ubsan/ubsan_diag.cc#L248.

有问题的源代码和 gdb 会话示例:

$ cat undef.c
int main(void) { return 1 << 1000; }
$ clang --version
clang version 3.6.2 (tags/RELEASE_362/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
$ clang -w -fsanitize=undefined undef.c -g
$ gdb -q -ex break\ __ubsan::ScopedReport::~ScopedReport -ex r ./a.out 
Reading symbols from ./a.out...done.
Breakpoint 1 at 0x428fb0
Starting program: ./a.out 
undef.c:1:27: runtime error: shift exponent 1000 is too large for 32-bit type 'int'

Breakpoint 1, 0x0000000000428fb0 in __ubsan::ScopedReport::~ScopedReport() ()
(gdb) bt
#0  0x0000000000428fb0 in __ubsan::ScopedReport::~ScopedReport() ()
#1  0x000000000042affb in handleShiftOutOfBoundsImpl(__ubsan::ShiftOutOfBoundsData*, unsigned long, unsigned long, __ubsan::ReportOptions) ()
#2  0x000000000042a952 in __ubsan_handle_shift_out_of_bounds ()
#3  0x000000000042d057 in main () at undef.c:1

详细分析如下。请注意,ASAN 和 ubsan 均源自 LLVM 项目,编译器-rt http://compiler-rt.llvm.org/。它由 Clang 使用,最终也出现在 GCC 中。以下部分中的链接指向编译器-rt 项目代码,版本 3.6。

ASAN 已经做出了内部__asan_report_error的一部分记录公共接口 https://github.com/llvm-mirror/compiler-rt/blob/release_36/include/sanitizer/asan_interface.h#L107。每当检测到违规时就会调用此函数,其流程继续lib/asan/asan_report.c:938 https://github.com/llvm-mirror/compiler-rt/blob/release_36/lib/asan/asan_report.cc#L938:

void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
                         uptr access_size) {
  // Determine the error type.
  const char *bug_descr = "unknown-crash";
  ...

  ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
                        bug_descr };
  ScopedInErrorReport in_report(&report);

  Decorator d;
  Printf("%s", d.Warning());
  Report("ERROR: AddressSanitizer: %s on address "
             "%p at pc %p bp %p sp %p\n",
             bug_descr, (void*)addr, pc, bp, sp);
  Printf("%s", d.EndWarning());

  u32 curr_tid = GetCurrentTidOrInvalid();
  char tname[128];
  Printf("%s%s of size %zu at %p thread T%d%s%s\n",
         d.Access(),
         access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
         access_size, (void*)addr, curr_tid,
         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
         d.EndAccess());

  GET_STACK_TRACE_FATAL(pc, bp);
  stack.Print();

  DescribeAddress(addr, access_size);
  ReportErrorSummary(bug_descr, &stack);
  PrintShadowMemoryForAddress(addr);
}

另一方面,ubsan 没有公共接口,但其当前的实现也更加简单和有限(选项较少)。出现错误时,可以打印堆栈跟踪UBSAN_OPTIONS=print_stacktrace=1环境变量已设置。因此,通过搜索源代码print_stacktrace, 找到函数也许是 PrintStackTrace https://github.com/llvm-mirror/compiler-rt/blob/release_36/lib/ubsan/ubsan_diag.cc#L25这被称为虽然ScopedReport 析构函数 https://github.com/llvm-mirror/compiler-rt/blob/release_36/lib/ubsan/ubsan_diag.cc#L351:

ScopedReport::~ScopedReport() {
  MaybePrintStackTrace(Opts.pc, Opts.bp);
  MaybeReportErrorSummary(SummaryLoc);
  CommonSanitizerReportMutex.Unlock();
  if (Opts.DieAfterReport || flags()->halt_on_error)
    Die();
}

正如您所看到的,有一种方法可以在出现错误时终止程序,但不幸的是没有内置机制来触发调试器陷阱。那我们就找一个合适的断点吧。

GDB命令info functions <function name> https://sourceware.org/gdb/onlinedocs/gdb/Symbols.html#index-info-functions-1071使得识别成为可能MaybePrintStackTrace作为可以设置断点的函数。执行info functions ScopedReport::~ScopedReport给出了另一个函数:__ubsan::ScopedReport::~ScopedReport。如果这些功能似乎都不可用(即使安装了调试符号),您可以尝试info functions ubsan or info functions sanitizer获取所有 (UndefinedBehaviorSanitizer 相关函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 gdb 中中断 UBSan 报告并继续? 的相关文章

  • Wpf TextBlock 中的垂直文本

    是否可以垂直显示 TextBlock 中的文本 以便所有字母彼此堆叠 不使用 LayoutTransform 旋转 还没有人提到使用纯 XAML 垂直堆叠任意字符串的字母 不旋转它们 的明显而简单的方法
  • SslStream.WriteAsync“当另一个写入操作挂起时,无法调用 BeginWrite 方法”

    异步向客户端写入数据时如何防止此问题 The BeginWrite method cannot be called when another write operation is pending MYCODE public async vo
  • 何时使用模拟框架?

    因此 我正在使用模拟框架 Moq 进行单元测试 并且想知道何时应该使用模拟框架 以下两个测试之间的优点 缺点是什么 public class Tests Fact public void TestWithMock Arrange var r
  • jQuery Datatable:分页和过滤器显示不正确

    我不知道如何解决这个问题 尝试了一整天但没有成功修复分页 我正在使用 jQuery 数据表 并且为了显示我的大量数据 我正在使用服务器端 作为测试 仅调用表中的 10 行数据 然后在传递到表之前 我重组了里面的数据dataSrc 使用这个解
  • C# 返回一个数的倍数和余数?

    我想找到给定数字的 3 的所有倍数 并找到余数 例如 给定数字 10 3 的倍数 3 6 9 余数 1 给定数字 11 3 的倍数 3 6 9 余数 2 到目前为止我的算法 但不是代码 是这样的 检查 X 是否是 3 的倍数 是 返回倍数
  • C 位域内存使用情况

    我需要处理以下形式的一些数据 typedef struct unsigned n1 12 unsigned n2 12 unsigned n3 12 unsigned n4 1 unsigned n5 35 data 我确保它们总共最多有
  • 如何在运行时添加到 TreeView 目录

    我有一个TreeView我想允许用户添加和删除子项目 在探索基本功能时 我使用button and a textbox添加此子项 当用户点击button a new TreeViewItem需要创建并设置为我的父项的子项TreeView与t
  • 静态方法中的统一

    一个可能很简单的问题 但很奇怪为什么我不知道该怎么做 Unity PRISM 和静态方法 在这种特殊情况下 需要使用扩展方法 但一般来说 如何在静态方法中访问 统一提供的实例 想想例如我想访问一个日志服务来记录我在静态方法中所做的一些事情
  • 编写/使用 C++ 库

    我正在寻找有关以下内容的基本示例 教程 如何用 C 编写 编译库 soLinux 的文件 dllWindows 文件 如何在其他代码中导入和使用这些库 The code r cc include t h int main f return
  • 编译时运算符

    有人可以列出 C 中可用的所有编译时运算符吗 C 中有两个运算符 无论操作数如何 它们的结果始终可以在编译时确定 它们是sizeof 1 and 2 当然 其他运算符的许多特殊用途可以在编译时解决 例如标准中列出的那些整数常量表达式 1 与
  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 按成员序列化

    我已经实现了template
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base

随机推荐