From ced25b5554a0fd920d71f7c169acb9434fa0d440 Mon Sep 17 00:00:00 2001 From: xhd2015 Date: Sat, 18 May 2024 18:28:52 +0800 Subject: [PATCH] add --trap-stdlib to support mock most stdlib functions --- cmd/xgo/exec_tool/debug.go | 1 + cmd/xgo/exec_tool/env.go | 2 + cmd/xgo/main.go | 37 +++++++--- cmd/xgo/option.go | 10 +++ cmd/xgo/runtime_gen/core/func.go | 3 + cmd/xgo/runtime_gen/core/version.go | 4 +- cmd/xgo/runtime_gen/functab/functab.go | 8 ++ cmd/xgo/runtime_gen/trace/stack.go | 12 ++- cmd/xgo/runtime_gen/trace/stack_export.go | 16 +++- cmd/xgo/runtime_gen/trap/trap.go | 1 + cmd/xgo/trace/stack_export.go | 16 +++- cmd/xgo/version.go | 4 +- patch/ctxt/ctx.go | 12 +-- patch/ctxt/env.go | 9 +++ patch/ctxt/stdlib.go | 32 ++++++++ patch/syntax/func_stub_def.go | 1 + patch/syntax/helper_code.go | 1 + patch/syntax/helper_code_gen.go | 10 +-- patch/syntax/syntax.go | 14 +++- runtime/core/func.go | 3 + runtime/core/version.go | 4 +- runtime/functab/functab.go | 8 ++ .../test/trap/stdlib_any/stdlib_any_test.go | 29 ++++++++ runtime/trace/stack.go | 12 ++- runtime/trace/stack_export.go | 16 +++- runtime/trap/trap.go | 1 + script/install/upgrade/upgrade.go | 73 ++++--------------- script/run-test/main.go | 6 ++ 28 files changed, 244 insertions(+), 101 deletions(-) create mode 100644 patch/ctxt/env.go create mode 100644 runtime/test/trap/stdlib_any/stdlib_any_test.go diff --git a/cmd/xgo/exec_tool/debug.go b/cmd/xgo/exec_tool/debug.go index 5eef5144..9e1f7aba 100644 --- a/cmd/xgo/exec_tool/debug.go +++ b/cmd/xgo/exec_tool/debug.go @@ -20,6 +20,7 @@ func getDebugEnv(xgoCompilerEnableEnv string) map[string]string { "GOCACHE": os.Getenv("GOCACHE"), XGO_MAIN_MODULE: os.Getenv(XGO_MAIN_MODULE), XGO_COMPILE_PKG_DATA_DIR: os.Getenv(XGO_COMPILE_PKG_DATA_DIR), + XGO_STD_LIB_TRAP_DEFAULT_ALLOW: os.Getenv(XGO_STD_LIB_TRAP_DEFAULT_ALLOW), "GOROOT": "../..", "PATH": "../../bin:${env:PATH}", "XGO_COMPILER_ENABLE": xgoCompilerEnableEnv, diff --git a/cmd/xgo/exec_tool/env.go b/cmd/xgo/exec_tool/env.go index 374875d6..a74eeacf 100644 --- a/cmd/xgo/exec_tool/env.go +++ b/cmd/xgo/exec_tool/env.go @@ -15,3 +15,5 @@ const XGO_TOOLCHAIN_VERSION_NUMBER = "XGO_TOOLCHAIN_VERSION_NUMBER" const XGO_MAIN_MODULE = "XGO_MAIN_MODULE" const XGO_COMPILE_PKG_DATA_DIR = "XGO_COMPILE_PKG_DATA_DIR" + +const XGO_STD_LIB_TRAP_DEFAULT_ALLOW = "XGO_STD_LIB_TRAP_DEFAULT_ALLOW" diff --git a/cmd/xgo/main.go b/cmd/xgo/main.go index 1bc6c2dd..3cefeacb 100644 --- a/cmd/xgo/main.go +++ b/cmd/xgo/main.go @@ -151,6 +151,7 @@ func handleBuild(cmd string, args []string) error { dumpIR := opts.dumpIR dumpAST := opts.dumpAST stackTrace := opts.stackTrace + trapStdlib := opts.trapStdlib if cmdExec && len(remainArgs) == 0 { return fmt.Errorf("exec requires command") @@ -241,8 +242,11 @@ func handleBuild(cmd string, args []string) error { // gcflags can cause the build cache to invalidate // so separate them with normal one buildCacheSuffix := "" + if trapStdlib { + buildCacheSuffix += "-trapstd" + } if len(gcflags) > 0 { - buildCacheSuffix = "-gcflags" + buildCacheSuffix += "-gcflags" } buildCacheDir := filepath.Join(instrumentDir, "build-cache"+buildCacheSuffix) revisionFile := filepath.Join(instrumentDir, "xgo-revision.txt") @@ -461,20 +465,33 @@ func handleBuild(cmd string, args []string) error { execCmd.Env = append(execCmd.Env, "XGO_TOOLCHAIN_VERSION="+VERSION) execCmd.Env = append(execCmd.Env, "XGO_TOOLCHAIN_REVISION="+REVISION) execCmd.Env = append(execCmd.Env, "XGO_TOOLCHAIN_VERSION_NUMBER="+strconv.FormatInt(NUMBER, 10)) - if dumpIR != "" { - execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_IR="+dumpIR) - execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_IR_FILE="+tmpIRFile) - } - if dumpAST != "" { - execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_AST="+dumpAST) - execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_AST_FILE="+tmpASTFile) - } + + // IR + execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_IR="+dumpIR) + execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_IR_FILE="+tmpIRFile) + + // AST + execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_AST="+dumpAST) + execCmd.Env = append(execCmd.Env, "XGO_DEBUG_DUMP_AST_FILE="+tmpASTFile) + + // vscode debug + var xgoDebugVscode string if vscodeDebugFile != "" { - execCmd.Env = append(execCmd.Env, "XGO_DEBUG_VSCODE="+vscodeDebugFile+vscodeDebugFileSuffix) + xgoDebugVscode = vscodeDebugFile + vscodeDebugFileSuffix } + execCmd.Env = append(execCmd.Env, "XGO_DEBUG_VSCODE="+xgoDebugVscode) + + // stack trace if stackTrace != "" { execCmd.Env = append(execCmd.Env, "XGO_STACK_TRACE="+stackTrace) } + + // trap stdlib + var trapStdlibEnv string + if trapStdlib { + trapStdlibEnv = "true" + } + execCmd.Env = append(execCmd.Env, "XGO_STD_LIB_TRAP_DEFAULT_ALLOW="+trapStdlibEnv) } logDebug("command env: %v", execCmd.Env) execCmd.Stdout = os.Stdout diff --git a/cmd/xgo/option.go b/cmd/xgo/option.go index 8c9a5f17..b1eceb92 100644 --- a/cmd/xgo/option.go +++ b/cmd/xgo/option.go @@ -50,6 +50,9 @@ type options struct { overlay string modfile string + // --trap-stdlib + trapStdlib bool + // xgo test --trace // --strace, --strace=on, --strace=off @@ -97,6 +100,7 @@ func parseOptions(args []string) (*options, error) { var overlay string var modfile string var stackTrace string + var trapStdlib bool var remainArgs []string nArg := len(args) @@ -254,6 +258,11 @@ func parseOptions(args []string) (*options, error) { continue } + if arg == "--trap-stdlib" { + trapStdlib = true + continue + } + if isDevelopment && arg == "--debug-with-dlv" { debugWithDlv = true continue @@ -340,6 +349,7 @@ func parseOptions(args []string) (*options, error) { overlay: overlay, modfile: modfile, stackTrace: stackTrace, + trapStdlib: trapStdlib, remainArgs: remainArgs, }, nil diff --git a/cmd/xgo/runtime_gen/core/func.go b/cmd/xgo/runtime_gen/core/func.go index b1b8bf2e..37f50205 100755 --- a/cmd/xgo/runtime_gen/core/func.go +++ b/cmd/xgo/runtime_gen/core/func.go @@ -51,6 +51,9 @@ type FuncInfo struct { // is this a closure? Closure bool + // is this function from stdlib + Stdlib bool + // source info File string Line int diff --git a/cmd/xgo/runtime_gen/core/version.go b/cmd/xgo/runtime_gen/core/version.go index 7c693e0c..b551c61a 100755 --- a/cmd/xgo/runtime_gen/core/version.go +++ b/cmd/xgo/runtime_gen/core/version.go @@ -7,8 +7,8 @@ import ( ) const VERSION = "1.0.35" -const REVISION = "3431198dea60ee1a41ed69b93034c5919aba32b5+1" -const NUMBER = 218 +const REVISION = "7742d22be893d673e6de160b6acc01b39502271e+1" +const NUMBER = 219 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/cmd/xgo/runtime_gen/functab/functab.go b/cmd/xgo/runtime_gen/functab/functab.go index a268ada1..d42e692b 100755 --- a/cmd/xgo/runtime_gen/functab/functab.go +++ b/cmd/xgo/runtime_gen/functab/functab.go @@ -169,6 +169,13 @@ func registerFuncInfo(fnInfo interface{}) { name := rv.FieldByName("Name").String() interface_ := rv.FieldByName("Interface").Bool() generic := rv.FieldByName("Generic").Bool() + + var stdlib bool + stdlibField := rv.FieldByName("Stdlib") + if stdlibField.IsValid() { + stdlib = stdlibField.Bool() + } + f := rv.FieldByName("Fn").Interface() var firstArgCtx bool @@ -222,6 +229,7 @@ func registerFuncInfo(fnInfo interface{}) { Interface: interface_, Generic: generic, Closure: closure, + Stdlib: stdlib, File: file, Line: line, diff --git a/cmd/xgo/runtime_gen/trace/stack.go b/cmd/xgo/runtime_gen/trace/stack.go index 4ff73e7a..635c838f 100755 --- a/cmd/xgo/runtime_gen/trace/stack.go +++ b/cmd/xgo/runtime_gen/trace/stack.go @@ -192,16 +192,20 @@ func ExportFuncInfo(c *core.FuncInfo, opts *ExportOptions) *FuncInfoExport { return nil } return &FuncInfoExport{ + Kind: FuncKind(c.Kind.String()), Pkg: c.Pkg, IdentityName: c.IdentityName, Name: c.Name, RecvType: c.RecvType, RecvPtr: c.RecvPtr, - Generic: c.Generic, - RecvName: c.RecvName, - ArgNames: c.ArgNames, - ResNames: c.ResNames, + Interface: c.Interface, + Generic: c.Generic, + Closure: c.Closure, + Stdlib: c.Stdlib, + RecvName: c.RecvName, + ArgNames: c.ArgNames, + ResNames: c.ResNames, FirstArgCtx: c.FirstArgCtx, LastResultErr: c.LastResultErr, diff --git a/cmd/xgo/runtime_gen/trace/stack_export.go b/cmd/xgo/runtime_gen/trace/stack_export.go index bc9f5e57..0612a05e 100755 --- a/cmd/xgo/runtime_gen/trace/stack_export.go +++ b/cmd/xgo/runtime_gen/trace/stack_export.go @@ -2,6 +2,15 @@ package trace import "time" +type FuncKind string + +const ( + FuncKind_Func FuncKind = "func" + FuncKind_Var FuncKind = "var" + FuncKind_VarPtr FuncKind = "var_ptr" + FuncKind_Const FuncKind = "const" +) + type RootExport struct { // current executed function Begin time.Time @@ -24,13 +33,18 @@ type StackExport struct { type FuncInfoExport struct { // FullName string + Kind FuncKind Pkg string IdentityName string Name string RecvType string RecvPtr bool - Generic bool + // interface method? + Interface bool + Generic bool + Closure bool + Stdlib bool File string Line int diff --git a/cmd/xgo/runtime_gen/trap/trap.go b/cmd/xgo/runtime_gen/trap/trap.go index 41bc7417..30ebf4ff 100755 --- a/cmd/xgo/runtime_gen/trap/trap.go +++ b/cmd/xgo/runtime_gen/trap/trap.go @@ -184,6 +184,7 @@ func trap(f *core.FuncInfo, pc uintptr, recv interface{}, args []interface{}, re var resetFlag bool parent := r.top + if !r.intercepting { resetFlag = true r.intercepting = true diff --git a/cmd/xgo/trace/stack_export.go b/cmd/xgo/trace/stack_export.go index cce75b7a..ed8d8454 100755 --- a/cmd/xgo/trace/stack_export.go +++ b/cmd/xgo/trace/stack_export.go @@ -4,6 +4,15 @@ package trace import "time" +type FuncKind string + +const ( + FuncKind_Func FuncKind = "func" + FuncKind_Var FuncKind = "var" + FuncKind_VarPtr FuncKind = "var_ptr" + FuncKind_Const FuncKind = "const" +) + type RootExport struct { // current executed function Begin time.Time @@ -26,13 +35,18 @@ type StackExport struct { type FuncInfoExport struct { // FullName string + Kind FuncKind Pkg string IdentityName string Name string RecvType string RecvPtr bool - Generic bool + // interface method? + Interface bool + Generic bool + Closure bool + Stdlib bool File string Line int diff --git a/cmd/xgo/version.go b/cmd/xgo/version.go index 91b205f2..61c497e8 100644 --- a/cmd/xgo/version.go +++ b/cmd/xgo/version.go @@ -3,8 +3,8 @@ package main import "fmt" const VERSION = "1.0.35" -const REVISION = "3431198dea60ee1a41ed69b93034c5919aba32b5+1" -const NUMBER = 218 +const REVISION = "7742d22be893d673e6de160b6acc01b39502271e+1" +const NUMBER = 219 func getRevision() string { revSuffix := "" diff --git a/patch/ctxt/ctx.go b/patch/ctxt/ctx.go index 65b55a27..1cc1db39 100644 --- a/patch/ctxt/ctx.go +++ b/patch/ctxt/ctx.go @@ -2,7 +2,6 @@ package ctxt import ( "cmd/compile/internal/base" - "os" "strings" ) @@ -11,9 +10,6 @@ const XgoRuntimePkg = XgoModule + "/runtime" const XgoRuntimeCorePkg = XgoModule + "/runtime/core" const XgoRuntimeTracePkg = XgoModule + "/runtime/trace" -var XgoMainModule = os.Getenv("XGO_MAIN_MODULE") -var XgoCompilePkgDataDir = os.Getenv("XGO_COMPILE_PKG_DATA_DIR") - const XgoLinkTrapVarForGenerated = "__xgo_link_trap_var_for_generated" func SkipPackageTrap() bool { @@ -21,7 +17,7 @@ func SkipPackageTrap() bool { if pkgPath == "" { return true } - if strings.HasPrefix(pkgPath, "runtime/") || strings.HasPrefix(pkgPath, "internal/") { + if pkgPath == "runtime" || strings.HasPrefix(pkgPath, "runtime/") || strings.HasPrefix(pkgPath, "internal/") { return true } if base.Flag.Std { @@ -37,6 +33,12 @@ func SkipPackageTrap() bool { // because generic instantiation happens in other package, so this // func may be a foreigner. + if XgoStdTrapDefaultAllow { + if _, ok := stdBlocklist[pkgPath]["*"]; ok { + return true + } + return false + } // allow http if _, ok := stdWhitelist[pkgPath]; ok { return false diff --git a/patch/ctxt/env.go b/patch/ctxt/env.go new file mode 100644 index 00000000..b69d5ec5 --- /dev/null +++ b/patch/ctxt/env.go @@ -0,0 +1,9 @@ +package ctxt + +import "os" + +var XgoMainModule = os.Getenv("XGO_MAIN_MODULE") +var XgoCompilePkgDataDir = os.Getenv("XGO_COMPILE_PKG_DATA_DIR") + +// enabled via: --trap-stdlib +var XgoStdTrapDefaultAllow = os.Getenv("XGO_STD_LIB_TRAP_DEFAULT_ALLOW") == "true" diff --git a/patch/ctxt/stdlib.go b/patch/ctxt/stdlib.go index 09a5393e..3e96d756 100644 --- a/patch/ctxt/stdlib.go +++ b/patch/ctxt/stdlib.go @@ -54,7 +54,39 @@ var stdWhitelist = map[string]map[string]bool{ }, } +// effective when XgoStdTrapDefaultAllow is true +// +// "net":map[string]bool{ +// "*": true -> disable all +// } +var stdBlocklist = map[string]map[string]bool{ + "syscall": map[string]bool{ + "*": true, + }, + "reflect": map[string]bool{ + "*": true, + }, + "sync": map[string]bool{ + "*": true, + }, + "sync/atomic": map[string]bool{ + "*": true, + }, + "testing": map[string]bool{ + "*": true, + }, + "unsafe": map[string]bool{ + "*": true, + }, +} + func allowStdFunc(pkgPath string, funcName string) bool { + if XgoStdTrapDefaultAllow { + if stdBlocklist[pkgPath]["*"] || stdBlocklist[pkgPath][funcName] { + return false + } + return true + } if stdWhitelist[pkgPath][funcName] { return true } diff --git a/patch/syntax/func_stub_def.go b/patch/syntax/func_stub_def.go index 2bb578d7..4c8e0e44 100644 --- a/patch/syntax/func_stub_def.go +++ b/patch/syntax/func_stub_def.go @@ -9,6 +9,7 @@ const expected__xgo_stub_def = `struct { Interface bool Generic bool Closure bool // is the given function a closure + Stdlib bool RecvTypeName string RecvPtr bool Name string diff --git a/patch/syntax/helper_code.go b/patch/syntax/helper_code.go index 2ccc65c5..a063345a 100644 --- a/patch/syntax/helper_code.go +++ b/patch/syntax/helper_code.go @@ -14,6 +14,7 @@ type __xgo_local_func_stub struct { Interface bool Generic bool Closure bool // is the given function a closure + Stdlib bool RecvTypeName string RecvPtr bool Name string diff --git a/patch/syntax/helper_code_gen.go b/patch/syntax/helper_code_gen.go index 3844a7a3..f2e340e1 100755 --- a/patch/syntax/helper_code_gen.go +++ b/patch/syntax/helper_code_gen.go @@ -11,6 +11,7 @@ const __xgo_stub_def = `struct { Interface bool Generic bool Closure bool // is the given function a closure + Stdlib bool RecvTypeName string RecvPtr bool Name string @@ -43,6 +44,7 @@ type __xgo_local_func_stub struct { Interface bool Generic bool Closure bool // is the given function a closure + Stdlib bool RecvTypeName string RecvPtr bool Name string @@ -92,10 +94,4 @@ func __xgo_local_register_func(pkgPath string, identityName string, fn interface __xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, IdentityName: identityName, Fn: fn, Closure: closure, RecvName: recvName, ArgNames: argNames, ResNames: resNames, File: file, Line: line}) } -func __xgo_trap_skip() {} - -// not used -// func __xgo_local_register_interface(pkgPath string, interfaceName string, file string, line int) { -// __xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, Interface: true, File: file, Line: line}) -// } -` +func __xgo_trap_skip() {}` diff --git a/patch/syntax/syntax.go b/patch/syntax/syntax.go index b0867632..0bec7577 100644 --- a/patch/syntax/syntax.go +++ b/patch/syntax/syntax.go @@ -41,7 +41,7 @@ func AfterFilesParsed(fileList []*syntax.File, addFile func(name string, r io.Re debugSyntax(fileList) patchVersions(fileList) fillFuncArgResNames(fileList) - registerFuncs(fileList, addFile) + registerAndTrapFuncs(fileList, addFile) } // typeinfo not used @@ -179,7 +179,7 @@ func ClearSyntaxDeclMapping() { syntaxDeclMapping = nil } -func registerFuncs(fileList []*syntax.File, addFile func(name string, r io.Reader) *syntax.File) { +func registerAndTrapFuncs(fileList []*syntax.File, addFile func(name string, r io.Reader) *syntax.File) { allFiles = fileList pkgPath := xgo_ctxt.GetPkgPath() @@ -237,6 +237,9 @@ func registerFuncs(fileList []*syntax.File, addFile func(name string, r io.Reade } // filterFuncDecls + // NOTE: stdlib is only available via source rewrite + // IR is turned off. + // so closure is not rewritten in stdlib funcDelcs = filterFuncDecls(funcDelcs, pkgPath) // assign to global allDecls = funcDelcs @@ -415,6 +418,7 @@ type DeclInfo struct { RecvPtr bool Generic bool Closure bool + Stdlib bool // this is an interface type declare // only the RecvTypeName is valid @@ -698,6 +702,8 @@ func getFuncDeclInfo(fileIndex int, f *syntax.File, file string, fn *syntax.Func RecvPtr: recvPtr, Generic: genericFunc || genericRecv, + Stdlib: base.Flag.Std, + RecvName: recvName, ArgNames: getFieldNames(fn.Type.ParamList), ResNames: getFieldNames(fn.Type.ResultList), @@ -756,7 +762,8 @@ func generateFuncRegBody(funcDecls []*DeclInfo, xgoRegFunc string, xgoLocalFuncS fileIdx := funcDecl.FileIndex fileRef := getFileRef(fileIdx) - // check __xgo_local_func_stub for correctness + // check expected__xgo_stub_def and __xgo_local_func_stub for correctness + var _ = expected__xgo_stub_def regKind := func(kind DeclKind, identityName string) { fieldList := []string{ XgoLocalPkgName, // PkgPath @@ -767,6 +774,7 @@ func generateFuncRegBody(funcDecls []*DeclInfo, xgoRegFunc string, xgoLocalFuncS strconv.FormatBool(funcDecl.Interface), // Interface strconv.FormatBool(funcDecl.Generic), // Generic strconv.FormatBool(funcDecl.Closure), // Closure + strconv.FormatBool(funcDecl.Stdlib), // Stdlib strconv.Quote(funcDecl.RecvTypeName), // RecvTypeName strconv.FormatBool(funcDecl.RecvPtr), // RecvPtr strconv.Quote(funcDecl.Name), // Name diff --git a/runtime/core/func.go b/runtime/core/func.go index b1b8bf2e..37f50205 100644 --- a/runtime/core/func.go +++ b/runtime/core/func.go @@ -51,6 +51,9 @@ type FuncInfo struct { // is this a closure? Closure bool + // is this function from stdlib + Stdlib bool + // source info File string Line int diff --git a/runtime/core/version.go b/runtime/core/version.go index 7c693e0c..b551c61a 100644 --- a/runtime/core/version.go +++ b/runtime/core/version.go @@ -7,8 +7,8 @@ import ( ) const VERSION = "1.0.35" -const REVISION = "3431198dea60ee1a41ed69b93034c5919aba32b5+1" -const NUMBER = 218 +const REVISION = "7742d22be893d673e6de160b6acc01b39502271e+1" +const NUMBER = 219 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/runtime/functab/functab.go b/runtime/functab/functab.go index a268ada1..d42e692b 100644 --- a/runtime/functab/functab.go +++ b/runtime/functab/functab.go @@ -169,6 +169,13 @@ func registerFuncInfo(fnInfo interface{}) { name := rv.FieldByName("Name").String() interface_ := rv.FieldByName("Interface").Bool() generic := rv.FieldByName("Generic").Bool() + + var stdlib bool + stdlibField := rv.FieldByName("Stdlib") + if stdlibField.IsValid() { + stdlib = stdlibField.Bool() + } + f := rv.FieldByName("Fn").Interface() var firstArgCtx bool @@ -222,6 +229,7 @@ func registerFuncInfo(fnInfo interface{}) { Interface: interface_, Generic: generic, Closure: closure, + Stdlib: stdlib, File: file, Line: line, diff --git a/runtime/test/trap/stdlib_any/stdlib_any_test.go b/runtime/test/trap/stdlib_any/stdlib_any_test.go new file mode 100644 index 00000000..fa6ef976 --- /dev/null +++ b/runtime/test/trap/stdlib_any/stdlib_any_test.go @@ -0,0 +1,29 @@ +package stdlib_any + +import ( + "os" + "testing" + + "github.com/xhd2015/xgo/runtime/mock" +) + +// build with --trap-stdlib + +func TestTrapStdlib(t *testing.T) { + var haveCalledMock bool + mock.Patch(os.UserHomeDir, func() (string, error) { + haveCalledMock = true + return "mock", nil + }) + + homeDir, err := os.UserHomeDir() + if !haveCalledMock { + t.Fatalf("mock not called") + } + if err != nil { + t.Fatal(err) + } + if homeDir != "mock" { + t.Fatalf("expect homeDir to be %q, actual: %q", "mock", homeDir) + } +} diff --git a/runtime/trace/stack.go b/runtime/trace/stack.go index 4ff73e7a..635c838f 100644 --- a/runtime/trace/stack.go +++ b/runtime/trace/stack.go @@ -192,16 +192,20 @@ func ExportFuncInfo(c *core.FuncInfo, opts *ExportOptions) *FuncInfoExport { return nil } return &FuncInfoExport{ + Kind: FuncKind(c.Kind.String()), Pkg: c.Pkg, IdentityName: c.IdentityName, Name: c.Name, RecvType: c.RecvType, RecvPtr: c.RecvPtr, - Generic: c.Generic, - RecvName: c.RecvName, - ArgNames: c.ArgNames, - ResNames: c.ResNames, + Interface: c.Interface, + Generic: c.Generic, + Closure: c.Closure, + Stdlib: c.Stdlib, + RecvName: c.RecvName, + ArgNames: c.ArgNames, + ResNames: c.ResNames, FirstArgCtx: c.FirstArgCtx, LastResultErr: c.LastResultErr, diff --git a/runtime/trace/stack_export.go b/runtime/trace/stack_export.go index bc9f5e57..0612a05e 100644 --- a/runtime/trace/stack_export.go +++ b/runtime/trace/stack_export.go @@ -2,6 +2,15 @@ package trace import "time" +type FuncKind string + +const ( + FuncKind_Func FuncKind = "func" + FuncKind_Var FuncKind = "var" + FuncKind_VarPtr FuncKind = "var_ptr" + FuncKind_Const FuncKind = "const" +) + type RootExport struct { // current executed function Begin time.Time @@ -24,13 +33,18 @@ type StackExport struct { type FuncInfoExport struct { // FullName string + Kind FuncKind Pkg string IdentityName string Name string RecvType string RecvPtr bool - Generic bool + // interface method? + Interface bool + Generic bool + Closure bool + Stdlib bool File string Line int diff --git a/runtime/trap/trap.go b/runtime/trap/trap.go index 41bc7417..30ebf4ff 100644 --- a/runtime/trap/trap.go +++ b/runtime/trap/trap.go @@ -184,6 +184,7 @@ func trap(f *core.FuncInfo, pc uintptr, recv interface{}, args []interface{}, re var resetFlag bool parent := r.top + if !r.intercepting { resetFlag = true r.intercepting = true diff --git a/script/install/upgrade/upgrade.go b/script/install/upgrade/upgrade.go index 6b0ef891..e410f630 100755 --- a/script/install/upgrade/upgrade.go +++ b/script/install/upgrade/upgrade.go @@ -6,15 +6,18 @@ import ( "context" "errors" "fmt" - "io" "io/fs" - "net/http" "os" "os/exec" "path/filepath" "runtime" "strings" + "time" + + "github.com/xhd2015/xgo/support/github" + "github.com/xhd2015/xgo/support/httputil" + "github.com/xhd2015/xgo/support/strutil" ) const latestURL = "https://github.com/xhd2015/xgo/releases/latest" @@ -185,78 +188,30 @@ func GetLatestVersion(ctx context.Context, timeout time.Duration, url string) (s ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - noRedirectClient := &http.Client{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - } - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - return "", err - } - resp, err := noRedirectClient.Do(req) - if err != nil { - return "", err - } - defer resp.Body.Close() - if resp.StatusCode != 302 { - return "", fmt.Errorf("expect 302 from %s", url) + releaseTag, _ := github.GetLatestReleaseTag(ctx, url) + if releaseTag != "" { + return strings.TrimPrefix(releaseTag, "v"), nil } - loc, err := resp.Location() + // old + path, err := httputil.Get302Location(ctx, url) if err != nil { return "", err } - - path := loc.Path - path, ok := trimLast(path, "/xgo-v") + path, ok := strutil.TrimBefore(path, "/xgo-v") if !ok { - path, ok = trimLast(path, "/tag/v") + path, ok = strutil.TrimBefore(path, "/tag/v") } if !ok || path == "" { - return "", fmt.Errorf("expect tag format: xgo-v1.x.x or tag/v1.x.x, actual: %s", loc.Path) + return "", fmt.Errorf("expect tag format: xgo-v1.x.x or tag/v1.x.x, actual: %s", path) } versionName := path return versionName, nil } -func trimLast(s string, p string) (string, bool) { - i := strings.LastIndex(s, p) - if i < 0 { - return s, false - } - return s[i+len(p):], true -} - func DownloadFile(ctx context.Context, timeout time.Duration, downloadURL string, targetFile string) error { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - req, err := http.NewRequestWithContext(ctx, "GET", downloadURL, nil) - if err != nil { - return err - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode == 404 { - return fmt.Errorf("%s not exists", downloadURL) - } - if resp.StatusCode != 200 { - data, _ := io.ReadAll(resp.Body) - return fmt.Errorf("failed: %s", data) - } - file, err := os.OpenFile(targetFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return err - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - return err - } - return nil + return httputil.DownloadFile(ctx, downloadURL, targetFile) } diff --git a/script/run-test/main.go b/script/run-test/main.go index 87fa6d29..f9b45271 100644 --- a/script/run-test/main.go +++ b/script/run-test/main.go @@ -91,6 +91,12 @@ var extraSubTests = []*TestCase{ dir: "runtime/test/trap_with_overlay", flags: []string{"-overlay", "overlay.json"}, }, + { + // see https://github.com/xhd2015/xgo/issues/111 + name: "trap_stdlib_any", + dir: "runtime/test/trap/stdlib_any", + flags: []string{"--trap-stdlib"}, + }, } func main() {