v: add an -assert aborts/backtraces option to ease debugging

pull/9756/head
Delyan Angelov 2021-04-15 20:26:51 +03:00
parent f0c1e55637
commit c7752ce8d3
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
3 changed files with 48 additions and 6 deletions

View File

@ -205,3 +205,13 @@ see also `v help build`.
Write all C flags into `file.txt`, one flag per line. Write all C flags into `file.txt`, one flag per line.
If `file.txt` is `-`, then write the flags to stdout, one flag per line. If `file.txt` is `-`, then write the flags to stdout, one flag per line.
-assert aborts
Call abort() after an assertion failure. Debuggers usually
install signal handlers for SIGABRT, so your program will stop and you
will get a backtrace. If you are running your program outside of a
debugger, you will most likely get a core dump file.
-assert backtraces
Call print_backtrace() after an assertion failure. Note that
backtraces are not implemented yet on all combinations of
platform/compiler.

View File

@ -33,9 +33,7 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
g.writeln('\tg_test_fails++;') g.writeln('\tg_test_fails++;')
metaname_fail := g.gen_assert_metainfo(node) metaname_fail := g.gen_assert_metainfo(node)
g.writeln('\tmain__cb_assertion_failed(&$metaname_fail);') g.writeln('\tmain__cb_assertion_failed(&$metaname_fail);')
if 'abort_on_assert' in g.pref.compile_defines_all { g.gen_assert_postfailure_mode(node)
g.writeln('\tabort();')
}
g.writeln('\tlongjmp(g_jump_buffer, 1);') g.writeln('\tlongjmp(g_jump_buffer, 1);')
g.writeln('\t// TODO') g.writeln('\t// TODO')
g.writeln('\t// Maybe print all vars in a test function if it fails?') g.writeln('\t// Maybe print all vars in a test function if it fails?')
@ -48,14 +46,24 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
g.writeln(' {') g.writeln(' {')
metaname_panic := g.gen_assert_metainfo(node) metaname_panic := g.gen_assert_metainfo(node)
g.writeln('\t__print_assert_failure(&$metaname_panic);') g.writeln('\t__print_assert_failure(&$metaname_panic);')
if 'abort_on_assert' in g.pref.compile_defines_all { g.gen_assert_postfailure_mode(node)
g.writeln('\tabort();')
}
g.writeln('\tv_panic(_SLIT("Assertion failed..."));') g.writeln('\tv_panic(_SLIT("Assertion failed..."));')
g.writeln('}') g.writeln('}')
} }
} }
fn (mut g Gen) gen_assert_postfailure_mode(node ast.AssertStmt) {
match g.pref.assert_failure_mode {
.default {}
.aborts {
g.writeln('\tabort();')
}
.backtraces {
g.writeln('\tprint_backtrace();')
}
}
}
fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt) string { fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt) string {
mod_path := cestring(g.file.path) mod_path := cestring(g.file.path)
fn_name := g.fn_decl.name fn_name := g.fn_decl.name

View File

@ -17,6 +17,12 @@ pub enum BuildMode {
build_module build_module
} }
pub enum AssertFailureMode {
default
aborts
backtraces
}
pub enum GarbageCollectionMode { pub enum GarbageCollectionMode {
no_gc no_gc
boehm_full // full garbage collection mode boehm_full // full garbage collection mode
@ -167,6 +173,7 @@ pub mut:
is_help bool // -h, -help or --help was passed is_help bool // -h, -help or --help was passed
gc_mode GarbageCollectionMode = .no_gc // .no_gc, .boehm, .boehm_leak, ... gc_mode GarbageCollectionMode = .no_gc // .no_gc, .boehm, .boehm_leak, ...
is_cstrict bool // turn on more C warnings; slightly slower is_cstrict bool // turn on more C warnings; slightly slower
assert_failure_mode AssertFailureMode // whether to call abort() or print_backtrace() after an assertion failure
// checker settings: // checker settings:
checker_match_exhaustive_cutoff_limit int = 10 checker_match_exhaustive_cutoff_limit int = 10
} }
@ -197,6 +204,23 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
res.arch = target_arch_kind res.arch = target_arch_kind
res.build_options << '$arg $target_arch' res.build_options << '$arg $target_arch'
} }
'-assert' {
assert_mode := cmdline.option(current_args, '-assert', '')
match assert_mode {
'aborts' {
res.assert_failure_mode = .aborts
}
'backtraces' {
res.assert_failure_mode = .backtraces
}
else {
eprintln('unknown assert mode `-gc $assert_mode`, supported modes are:`')
eprintln(' `-assert aborts` .... calls abort() after assertion failure')
eprintln(' `-assert backtraces` .... calls print_backtrace() after assertion failure')
exit(1)
}
}
}
'-show-timings' { '-show-timings' {
res.show_timings = true res.show_timings = true
} }