From 099040eb391e8186e1bafd1906cb9dc01e20f07c Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:05:24 +0200 Subject: [PATCH] builtin: fix compiling with tcc showing v_stable_sort for all frames (#27417) --- vlib/builtin/backtraces_nix.c.v | 124 +++++++++++--------- vlib/builtin/builtin.c.v | 4 +- vlib/builtin/builtin_d_use_libbacktrace.c.v | 27 +++-- vlib/builtin/panicing.c.v | 34 +++--- 4 files changed, 104 insertions(+), 85 deletions(-) diff --git a/vlib/builtin/backtraces_nix.c.v b/vlib/builtin/backtraces_nix.c.v index e1a38a487..b48a4ea7e 100644 --- a/vlib/builtin/backtraces_nix.c.v +++ b/vlib/builtin/backtraces_nix.c.v @@ -163,6 +163,18 @@ fn backtrace_addr2line_executable(executable string, current_executable_name str return executable } +fn backtrace_shell_quote(s string) string { + mut quoted := "'" + for i in 0 .. s.len { + if s[i] == `'` { + quoted += "'\\''" + } else { + quoted += s[i].ascii_str() + } + } + return quoted + "'" +} + @[direct_array_access] fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { $if android { @@ -173,69 +185,69 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { return false } $else { $if linux && !freestanding { - $if tinyc { - C.tcc_backtrace(c'Backtrace') - return false - } $else { - $if !glibc { + $if !glibc { + $if tinyc { + C.tcc_backtrace(c'Backtrace') + } $else { eprintln('backtrace_symbols is missing => printing backtraces is not available.') eprintln('Some libc implementations like musl simply do not provide it.') + } + return false + } $else { + current_executable_name := backtrace_current_executable_name() + buffer := [100]voidptr{} + nr_ptrs := C.backtrace(&buffer[0], 100) + if nr_ptrs < 2 { + eprintln('C.backtrace returned less than 2 frames') return false - } $else { - current_executable_name := backtrace_current_executable_name() - buffer := [100]voidptr{} - nr_ptrs := C.backtrace(&buffer[0], 100) - if nr_ptrs < 2 { - eprintln('C.backtrace returned less than 2 frames') - return false + } + nr_actual_frames := nr_ptrs - skipframes + //////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames) + csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames) + for i in 0 .. nr_actual_frames { + sframe := unsafe { tos2(&u8(csymbols[i])) } + executable := sframe.all_before('(') + addr2line_executable := backtrace_addr2line_executable(executable, + current_executable_name) + addr := sframe.all_after('[').all_before(']') + beforeaddr := sframe.all_before('[') + cmd := 'addr2line -e ' + backtrace_shell_quote(addr2line_executable) + ' ' + + backtrace_shell_quote(addr) + // taken from os, to avoid depending on the os module inside builtin.v + f := C.popen(&char(cmd.str), c'r') + if f == unsafe { nil } { + eprintln(sframe) + continue } - nr_actual_frames := nr_ptrs - skipframes - //////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames) - csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames) - for i in 0 .. nr_actual_frames { - sframe := unsafe { tos2(&u8(csymbols[i])) } - executable := sframe.all_before('(') - addr2line_executable := backtrace_addr2line_executable(executable, - current_executable_name) - addr := sframe.all_after('[').all_before(']') - beforeaddr := sframe.all_before('[') - cmd := 'addr2line -e ' + addr2line_executable + ' ' + addr - // taken from os, to avoid depending on the os module inside builtin.v - f := C.popen(&char(cmd.str), c'r') - if f == unsafe { nil } { - eprintln(sframe) - continue - } - buf := [1000]u8{} - mut output := '' - unsafe { - bp := &u8(&buf[0]) - for C.fgets(&char(bp), 1000, f) != 0 { - output += tos(bp, vstrlen(bp)) - } - } - output = output.trim_chars(' \t\n', .trim_both) + ':' - if C.pclose(f) != 0 { - eprintln(sframe) - continue - } - if output in ['??:0:', '??:?:'] { - output = '' + buf := [1000]u8{} + mut output := '' + unsafe { + bp := &u8(&buf[0]) + for C.fgets(&char(bp), 1000, f) != 0 { + output += tos(bp, vstrlen(bp)) } - // See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators - // Note: it is shortened here to just d. , just so that it fits, and so - // that the common error file:lineno: line format is enforced. - output = output.replace(' (discriminator', ': (d.') - eprint(output) - eprint_space_padding(output, 55) - eprint(' | ') - eprint(addr) - eprint(' | ') - eprintln(demangle_backtrace_sym(beforeaddr)) } - if nr_actual_frames > 0 { - unsafe { C.free(csymbols) } + output = output.trim_chars(' \t\n', .trim_both) + ':' + if C.pclose(f) != 0 { + eprintln(sframe) + continue + } + if output in ['??:0:', '??:?:'] { + output = '' } + // See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators + // Note: it is shortened here to just d. , just so that it fits, and so + // that the common error file:lineno: line format is enforced. + output = output.replace(' (discriminator', ': (d.') + eprint(output) + eprint_space_padding(output, 55) + eprint(' | ') + eprint(addr) + eprint(' | ') + eprintln(demangle_backtrace_sym(beforeaddr)) + } + if nr_actual_frames > 0 { + unsafe { C.free(csymbols) } } } } diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index bd0a4d5d4..fb9b1238e 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -60,12 +60,14 @@ fn v_segmentation_fault_handler(signal_number i32) { } $else { C.fprintf(C.stderr, c'signal %d: segmentation fault\n', signal_number) } - $if use_libbacktrace ? { + $if use_libbacktrace ? && !tinyc { $if openbsd { print_backtrace() } $else { eprint_libbacktrace(1) } + } $else $if tinyc && glibc { + print_backtrace_skipping_top_frames(1) } $else { print_backtrace() } diff --git a/vlib/builtin/builtin_d_use_libbacktrace.c.v b/vlib/builtin/builtin_d_use_libbacktrace.c.v index 7c9df4575..9fb9e9a5d 100644 --- a/vlib/builtin/builtin_d_use_libbacktrace.c.v +++ b/vlib/builtin/builtin_d_use_libbacktrace.c.v @@ -10,7 +10,8 @@ $if openbsd { @[noinline] fn eprint_libbacktrace(frames_to_skip int) { } -} $else { +} $else $if !tinyc { + // full libbacktrace implementation for gcc/clang (TCC can't compile libbacktrace's C code) #flag -I@VEXEROOT/thirdparty/libbacktrace #flag @VEXEROOT/thirdparty/libbacktrace/backtrace.o #include @@ -31,16 +32,13 @@ $if openbsd { __global bt_state = init_bt_state() fn init_bt_state() &C.backtrace_state { - $if !tinyc { - mut filename := &char(unsafe { nil }) - $if windows { - filename = unsafe { string_from_wide(&&u16(g_main_argv)[0]).str } - } $else { - filename = unsafe { &&char(g_main_argv)[0] } - } - return C.backtrace_create_state(filename, 1, bt_error_handler, 0) + mut filename := &char(unsafe { nil }) + $if windows { + filename = unsafe { string_from_wide(&&u16(g_main_argv)[0]).str } + } $else { + filename = unsafe { &&char(g_main_argv)[0] } } - return &C.backtrace_state(unsafe { nil }) + return C.backtrace_create_state(filename, 1, bt_error_handler, 0) } // for bt_error_callback @@ -116,4 +114,13 @@ $if openbsd { } C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data) } +} $else { + // no-op stubs for TCC (TCC can't compile libbacktrace's C code, and + // it has its own built-in backtrace via tcc_backtrace instead) + fn print_libbacktrace(frames_to_skip int) { + } + + @[noinline] + fn eprint_libbacktrace(frames_to_skip int) { + } } diff --git a/vlib/builtin/panicing.c.v b/vlib/builtin/panicing.c.v index c62d3d94f..94c051dfc 100644 --- a/vlib/builtin/panicing.c.v +++ b/vlib/builtin/panicing.c.v @@ -42,16 +42,15 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { C.exit(1) } $else $if no_backtrace ? { C.exit(1) - } $else { - $if tinyc { - $if panics_break_into_debugger ? { - break_if_debugger_attached() - } $else { - C.tcc_backtrace(c'Backtrace') - } - C.exit(1) + } $else $if tinyc && !glibc { + $if panics_break_into_debugger ? { + break_if_debugger_attached() + } $else { + C.tcc_backtrace(c'Backtrace') } - $if use_libbacktrace ? { + C.exit(1) + } $else { + $if use_libbacktrace ? && !tinyc { $if openbsd { print_backtrace_skipping_top_frames(1) } $else { @@ -114,16 +113,15 @@ pub fn panic(s string) { C.exit(1) } $else $if no_backtrace ? { C.exit(1) - } $else { - $if tinyc { - $if panics_break_into_debugger ? { - break_if_debugger_attached() - } $else { - C.tcc_backtrace(c'Backtrace') - } - C.exit(1) + } $else $if tinyc && !glibc { + $if panics_break_into_debugger ? { + break_if_debugger_attached() + } $else { + C.tcc_backtrace(c'Backtrace') } - $if use_libbacktrace ? { + C.exit(1) + } $else { + $if use_libbacktrace ? && !tinyc { $if openbsd { print_backtrace_skipping_top_frames(1) } $else { -- 2.39.5