如何在 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 报告并继续? 的相关文章

  • 为什么在 lambda 内部引发异常是 C# 7 的一项功能? [复制]

    这个问题在这里已经有答案了 该语句在 VS2015 中无法编译 但在 VS2017 中可以编译 var example new Action gt throw new Exception 为了支持在 lambda 表达式内抛出异常 必须对
  • 线程独占数据:如何存储和访问?

    NET 中是否有可能将对象实例绑定到线程的当前执行上下文 这样在代码的任何部分我都可以做类似的事情CurrentThread MyObjectData DoOperation 并确保我访问特定于线程的数据 谢谢 你可以看一下线程静态属性 h
  • 等待运算符错误

    我的代码有问题 我怎么解决这个问题 这个问题出现在await操作符中 public MyModel HttpClient client new HttpClient HttpResponseMessage response await cl
  • 为什么 fgets 接受 int 而不是 size_t?

    功能如strcpy malloc strlen 和其他各种接受他们的参数或返回值作为size t代替int or an unsigned int出于显而易见的原因 一些文件功能 例如fread and fwrite use size t以及
  • 带有嵌入 Flash 视频的 PDF 示例?

    有谁知道我在哪里可以查看嵌入 Flash 视频的 PDF 示例 我知道问这个问题很愚蠢 因为你会认为任何面向技术的用户都应该能够使用谷歌找到一个 但我真的找不到 我的另一个问题是 使用 C 中的 API 将 Flash 视频嵌入 PDF 文
  • C++ 并行任务的开销

    我有以下简单的功能 include
  • UI 线程正在阻塞调用 COM 对象的后台线程

    我正在开发一个通过第三方 COM 库与外部设备通信的应用程序 我试图让与设备的所有通信都通过后台线程 以防止通信问题搞砸我的应用程序 并消除在 UI 线程中进行通信所引入的一些其他复杂性 问题是 每当发生导致主 UI 线程阻塞的情况 即调用
  • 用 OpenCL C 编写快速线性系统求解器

    我正在编写一个 OpenCL 内核 它将涉及求解线性系统 目前我的内核太慢了 提高线性系统部分的性能似乎是一个不错的起点 我还应该注意 我并没有尝试使我的线性求解器并行 我正在研究的问题在宏观层面上已经是令人尴尬的并行 以下是我编写的 C
  • 在 Linq 查询中使用动态列名称

    foreach Dimension dimensions in Enum GetValues typeof Dimension var r new ReferenceTable dimensions referenceItems List
  • 使用 FromBase64Transform 解码 base64 文件流

    The example https msdn microsoft com en us library system security cryptography frombase64transform 28v vs 110 29 aspx从M
  • 将旧的 Unity 代码升级到 Unity 5

    在触发按钮上播放动画的代码似乎不起作用 我在 Youtube 上看到了一个视频 内容很简单animation Play 它可以在该视频上运行 但我无法让它在我的计算机上运行 我做错了什么还是团结改变了它 请帮助我在网上找不到解决方案 所有
  • ef core 在更新数据库期间不使用 ASPNETCORE_ENVIRONMENT

    我使用 Visual Studio 通过一定的迁移来更新我的所有环境 使用下面的命令效果很好 update database Migration initMigrationProduct c ProductContext Environme
  • 解析连接字符串

    是否有标准库或代码片段可以使用这样的连接字符串获取值 string connstr DataServiceUrl http localhost foo RemoteServerConnection server http localhost
  • “DeploymentItem”属性是什么意思?

    假设我们有一个简短的程序 namespace ConsoleTryIt static class Program static void Main string args var sum Add 1 2 private static int
  • 当分配返回 0 时,具有空异常规范的运算符 new 调用构造函数

    我有以下声明 void operator new size t s PersistentMemory m throw return m gt allocatePersistentMemory s 我正在测试启动时的内存耗尽 这会导致m gt
  • 调用泛型类的方法

    这是上下文 我尝试编写一个映射器来动态地将域模型对象转换为 ViewModel 对象 我遇到的问题是 当我尝试通过反射调用泛型类的方法时 出现此错误 System InvalidOperationException 无法对 Contains
  • 打印任何类型的数组和列表的通用方法[重复]

    这个问题在这里已经有答案了 每当我调试一段涉及整数 双精度 字符串等数组或列表的代码时 有时我更喜欢打印它们 我为此所做的是为不同类型编写重载的 printArray printList 方法 for e g 我可能有这 3 种方法来打印各
  • 如何从 C# 中的 Web Api 方法正确获取字节数组?

    我有以下控制器方法 HttpPost Route SomeRoute public byte MyMethod FromBody string ID byte mybytearray db getmybytearray ID working
  • Selenium - 模式对话框存在 - 如何接受信息?

    我有以下问题 在页面上提交一些日期后 我有一个如图所示的模式对话框 我想单击 ENTER 来浏览该模式 但它不起作用 我有以下代码 driver FindElement By CssSelector input submit Click A
  • 推断“x => { throw .. }”的 Lambda 与重载方法中的 Func 匹配吗?

    我不明白为什么 C 最终在以下 LINQPad 代码中执行不正确的扩展方法 void Main Actual Sync Action Expected Sync Action Run x gt x Dump Actual Async Tas

随机推荐