问题描述
最近的GCC和Clang版本的特性是Undefined Behavior Sanitizer(UBSan),它是一个编译标志( -fsanitize = undefined
),它增加了运行时检测代码。出现错误时,会显示如下所示的警告: 现在我想调试这个,并得到一个调试休息说线。对于Address Sanitizer(ASAN),存在 ASAN_OPTIONS = abort_on_error = 1
,这会导致可捕获的致命错误。唯一可用的UBSan选项是会导致报告的调用跟踪转储。但是,这不允许我检查局部变量,然后继续执行程序。因此,使用 -fsanitize-undefined-trap-on-error
是不可能的。 在UBSan的报告?虽然 break __sanitizer :: SharedPrintfCode
似乎起作用,但名字看起来相当内在。
打破检测功能(如和)是一种选择,更好的方法是打破检测后报告这些问题的功能。这种方法也适用于ASAN,其中一个会在 __ asan_report_error
上突破。
摘要:您可以停止使用ubsan通过 __ ubsan :: ScopedReport ::〜ScopedReport
或 __ ubsan :: Diag ::〜诊断
即可。这些是未来可能会改变的私人实施细节。使用GCC 4.9,5.1.0,5.2.0和Clang 3.3,3.4,3.6.2进行测试。
对于GCC 4.9.2来自,您需要 libubsan0 -dbg
使上述断点可用。使用Clang 3.3和3.4的Ubuntu 14.04不支持 __ ubsan :: ScopedReport ::〜ScopedReport
断点,因此只能在使用。
示例buggy源代码和gdb会话:
$ cat undef.c
int main(void){return 1 $ clang --version
clang版本3.6.2(tags / RELEASE_362 / final)
目标:x86_64-unknown-linux-gnu
线程模型:posix
$ clang -w -fsanitize = undefined undef.c -g
$ gdb -q -ex break\ __ubsan :: ScopedReport ::〜ScopedReport -ex r ./a.out
从./a.out...done。
在0x428fb0处的断点1
启动程序:./a.out
undef.c:1:27:运行时错误:移位指数1000对于32位类型'int'$太大在__ubsan :: ScopedReport ::〜ScopedReport()中,b
$ b断点1,0x0000000000428fb0在__ubsan :: ScopedReport ::〜ScopedReport()()中
(gdb)bt
#0 0x0000000000428fb0。 ()
#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项目,。这被Clang使用,并最终在GCC中结束。以下各节中的链接指向编译器-rt项目代码,版本3.6。
ASAN已将其内部的 __ asan_report_error
的一部分。无论何时检测到违例,都会调用此函数,其流程将在:
void __asan_report_error(uptr pc,uptr bp,uptr sp, uptr addr,int is_write,
uptr access_size){
//确定错误类型。
const char * bug_descr =unknown-crash;
...
ReportData报告= {pc,sp,bp,addr,(bool)is_write,access_size,
bug_descr};
ScopedInErrorReport in_report(& report);
装饰者d;
Printf(%s,d.Warning());
报告(ERROR:AddressSanitizer:%s on address
%p at pc%p bp%p sp%p \\\
,
bug_descr,(void *)addr, pc,bp,sp);
Printf(%s,d.EndWarning());
u32 curr_tid = GetCurrentTidOrInvalid();
char tname [128];
Printf(%s%s%s%at%p thread T%d%s%s \\\
,
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没有公共接口,但其当前的实现也是更简单和有限(更少的选项)。出现错误时,可以在设置 正如你所看到的,有一种方法可以在错误时终止程序,但不幸的是,没有内建机制来触发调试器陷阱。让我们找到合适的断点。 GDB命令可以识别 Recent versions of GCC and Clang feature Undefined Behavior Sanitizer (UBSan) which is a compile flag ( Now I would like to debug this and get a debug break on said line. For Address Sanitizer (ASAN) there is How should I break in gdb on UBSan reports? While While breaking on the detection functions (as described by @Mark Plotnick and @Iwillnotexist Idonotexist) is one option, a better approach is breaking on the functions that report these issues after detection. This approach is also used for ASAN where one would break on Summary: You can stop on an ubsan report via a breakpoint on For GCC 4.9.2 from ppa:ubuntu-toolchain-r/test, you need Example buggy source code and a gdb session: Detailled analysis follows. Note that both ASAN and ubsan both originate from a LLVM project, compiler-rt. This is used by Clang and ends up in GCC as well. Links in the following sections point to the compiler-rt project code, release 3.6. ASAN has made its internal ubsan on the other hand has no public interface, but its current implementation is also much simpler and limited (less options). On errors, a stacktrace can be printed when the As you can see, there is a method to kill the program on errors, but unfortunately there is no builtin mechanism to trigger a debugger trap. Let's find a suitable breakpoint then. The GDB command 这篇关于我如何在gdb中打破UBSan报告并继续?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! UBSAN_OPTIONS = print_stacktrace = 1
环境变量时打印堆栈跟踪。因此,通过搜索 print_stacktrace
的源代码,可以找到函数,通过:
$ b $ pre $ ScopedReport ::〜ScopedReport(){
MaybePrintStackTrace(Opts.pc,Opts.bp);
MaybeReportErrorSummary(SummaryLoc);
CommonSanitizerReportMutex.Unlock();
if(Opts.DieAfterReport || flags() - > halt_on_error)
Die();
$ b
MaybePrintStackTrace
作为可以设置断点的函数。执行 info函数ScopedReport ::〜ScopedReport
给出了另一个函数: __ ubsan :: ScopedReport ::〜ScopedReport
。如果这些函数都不可用(即使安装了调试符号),您可以尝试 info functions ubsan
或 info functions sanitizer
获取所有(UndefinedBehavior)Sanitizer相关函数。-fsanitize=undefined
) that adds runtime instrumentation code. On errors, a warning such as this one is shown:ASAN_OPTIONS=abort_on_error=1
which results in a fatal error that is catchable. The only UBSan option that seems usable is UBSAN_OPTIONS=print_stacktrace=1
which results in a call trace dump for reports. This however does not allow me to inspect the local variables and then continue the program. Use of -fsanitize-undefined-trap-on-error
therefore not possible.break __sanitizer::SharedPrintfCode
seems to work, the name looks quite internal.__asan_report_error
.__ubsan::ScopedReport::~ScopedReport
or __ubsan::Diag::~Diag
. These are private implementation details which might change in the future though. Tested with GCC 4.9, 5.1.0, 5.2.0 and Clang 3.3, 3.4, 3.6.2.libubsan0-dbg
to make the above breakpoints available. Ubuntu 14.04 with Clang 3.3 and 3.4 do not support the __ubsan::ScopedReport::~ScopedReport
breakpoints, so you can only break before printing the message using __ubsan::Diag::~Diag
.$ 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_report_error
part of the documented public interface. This function gets called whenever a violation is detected, its flow continues in lib/asan/asan_report.c:938: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_OPTIONS=print_stacktrace=1
environment variable is set. Thus, by searching the source code for print_stacktrace
, one finds function MaybePrintStackTrace which is called though the ScopedReport destructor:ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
MaybeReportErrorSummary(SummaryLoc);
CommonSanitizerReportMutex.Unlock();
if (Opts.DieAfterReport || flags()->halt_on_error)
Die();
}
info functions <function name>
made it possible to identify MaybePrintStackTrace
as function on which a breakpoint can be set. Execution of info functions ScopedReport::~ScopedReport
gave another function: __ubsan::ScopedReport::~ScopedReport
. If none of these functions seem available (even with debugging symbols installed), you can try info functions ubsan
or info functions sanitizer
to get all (UndefinedBehavior)Sanitizer-related functions.