From 55c5b9ce7bb06285752f52f14a9b0f5952171abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sun, 25 Jul 2021 00:13:34 +0200 Subject: [PATCH] cgen: panic with error message when `go` command fails (#10943) --- vlib/builtin/builtin.c.v | 23 +++++++++++++++++++++++ vlib/builtin/builtin_nix.c.v | 8 ++++++++ vlib/builtin/builtin_windows.c.v | 25 +++++++++++++++++++++++++ vlib/v/checker/checker.v | 2 +- vlib/v/gen/c/cgen.v | 4 +++- vlib/v/markused/markused.v | 1 + vlib/v/markused/walker.v | 9 +++++++++ 7 files changed, 70 insertions(+), 2 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index c8766372c7..552087328e 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -3,6 +3,7 @@ module builtin type FnExitCb = fn () fn C.atexit(f FnExitCb) int +fn C.strerror(int) &char [noreturn] fn vhalt() { @@ -100,6 +101,28 @@ pub fn panic(s string) { vhalt() } +// return a C-API error message matching to `errnum` +pub fn c_error_number_str(errnum int) string { + mut err_msg := '' + $if freestanding { + err_msg = 'error $errnum' + } $else { + c_msg := C.strerror(errnum) + err_msg = string{ + str: &byte(c_msg) + len: unsafe { C.strlen(c_msg) } + is_lit: 1 + } + } + return err_msg +} + +// panic with a C-API error message matching `errnum` +[noreturn] +pub fn panic_error_number(basestr string, errnum int) { + panic(basestr + c_error_number_str(errnum)) +} + // eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed. pub fn eprintln(s string) { if s.str == 0 { diff --git a/vlib/builtin/builtin_nix.c.v b/vlib/builtin/builtin_nix.c.v index 57ac7515d7..0d79af4f9a 100644 --- a/vlib/builtin/builtin_nix.c.v +++ b/vlib/builtin/builtin_nix.c.v @@ -134,3 +134,11 @@ fn break_if_debugger_attached() { _ = ptr } } + +// These functions are Windows specific - provide dummys for *nix +pub fn winapi_lasterr_str() string { + return '' +} + +[noreturn] +pub fn panic_lasterr() {} diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index 9e2ffa744f..741009c326 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -54,6 +54,8 @@ fn C.SymFromAddr(h_process voidptr, address u64, p_displacement voidptr, p_symbo fn C.SymGetLineFromAddr64(h_process voidptr, address u64, p_displacement voidptr, p_line &Line64) int +fn C.FormatMessage(dwFlags u32, lpSource voidptr, dwMessageId u32, dwLanguageId u32, lpBuffer &voidptr, nSize u32, Arguments voidptr) u32 + // Ref - https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions const ( symopt_undname = 0x00000002 @@ -277,3 +279,26 @@ fn break_if_debugger_attached() { } } } + +// return an error message generated from WinAPI's `LastError` +pub fn winapi_lasterr_str() string { + mut msgbuf := &byte(0) + err_msg_id := C.GetLastError() + res := C.FormatMessage(C.FORMAT_MESSAGE_ALLOCATE_BUFFER | C.FORMAT_MESSAGE_FROM_SYSTEM, + C.NULL, err_msg_id, 0, &msgbuf, 0, C.NULL) + err_msg := if res == 0 { + 'unknown error $err_msg_id' + } else { + string{ + str: msgbuf + len: int(res) + } + } + return err_msg +} + +// panic with an error message generated from WinAPI's `LastError` +[noreturn] +pub fn panic_lasterr(base string) { + panic(base + winapi_lasterr_str()) +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e0b0dc2347..e7cb960b83 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -6597,7 +6597,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } c.skip_flags = cur_skip_flags if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 { - c.ct_cond_stack.pop() + c.ct_cond_stack.delete_last() } } else { // smartcast sumtypes and interfaces when using `is` diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 59a4cf6351..f36a692ee7 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6087,6 +6087,7 @@ fn (mut g Gen) go_expr(node ast.GoExpr) { 'thread_$tmp' } g.writeln('HANDLE $simple_handle = CreateThread(0,0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0,0);') + g.writeln('if (!$simple_handle) panic_lasterr(tos3("`go ${name}()`: "));') if node.is_expr && node.call_expr.return_type != ast.void_type { g.writeln('$gohandle_name thread_$tmp = {') g.writeln('\t.ret_ptr = $arg_tmp_var->ret_ptr,') @@ -6098,7 +6099,8 @@ fn (mut g Gen) go_expr(node ast.GoExpr) { } } else { g.writeln('pthread_t thread_$tmp;') - g.writeln('pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);') + g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);') + g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);') if !node.is_expr { g.writeln('pthread_detach(thread_$tmp);') } diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 2d911394f6..a1fbcad6f1 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -280,6 +280,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F files: ast_files all_fns: all_fns all_consts: all_consts + pref: pref } // println( all_fns.keys() ) walker.mark_exported_fns() diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index 4031589ae9..680ffbb829 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -5,6 +5,7 @@ module markused // Walk the entire program starting at fn main and marks used (called) functions. // Unused functions can be safely skipped by the backends to save CPU time and space. import v.ast +import v.pref pub struct Walker { pub mut: @@ -12,6 +13,7 @@ pub mut: used_fns map[string]bool // used_fns['println'] == true used_consts map[string]bool // used_consts['os.args'] == true n_asserts int + pref &pref.Preferences mut: files []&ast.File all_fns map[string]ast.FnDecl @@ -213,6 +215,13 @@ fn (mut w Walker) expr(node ast.Expr) { } ast.GoExpr { w.expr(node.call_expr) + if w.pref.os == .windows { + w.fn_by_name('panic_lasterr') + w.fn_by_name('winapi_lasterr_str') + } else { + w.fn_by_name('c_error_number_str') + w.fn_by_name('panic_error_number') + } } ast.IndexExpr { w.expr(node.left)