From 7b4377ad9d8a7205416df8d6217ef2b010f89481 Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Wed, 22 Jan 2025 16:07:17 +0100 Subject: vendor: delete --- vendor/github.com/kkHAIKE/contextcheck/.gitignore | 20 - vendor/github.com/kkHAIKE/contextcheck/LICENSE | 201 ----- vendor/github.com/kkHAIKE/contextcheck/Makefile | 15 - vendor/github.com/kkHAIKE/contextcheck/README.md | 157 ---- .../kkHAIKE/contextcheck/contextcheck.go | 825 --------------------- 5 files changed, 1218 deletions(-) delete mode 100644 vendor/github.com/kkHAIKE/contextcheck/.gitignore delete mode 100644 vendor/github.com/kkHAIKE/contextcheck/LICENSE delete mode 100644 vendor/github.com/kkHAIKE/contextcheck/Makefile delete mode 100644 vendor/github.com/kkHAIKE/contextcheck/README.md delete mode 100644 vendor/github.com/kkHAIKE/contextcheck/contextcheck.go (limited to 'vendor/github.com/kkHAIKE/contextcheck') diff --git a/vendor/github.com/kkHAIKE/contextcheck/.gitignore b/vendor/github.com/kkHAIKE/contextcheck/.gitignore deleted file mode 100644 index 1c2ffa5f4..000000000 --- a/vendor/github.com/kkHAIKE/contextcheck/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -.idea -.DS_Store - -/contextcheck diff --git a/vendor/github.com/kkHAIKE/contextcheck/LICENSE b/vendor/github.com/kkHAIKE/contextcheck/LICENSE deleted file mode 100644 index 99e1c482a..000000000 --- a/vendor/github.com/kkHAIKE/contextcheck/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 sylvia.wang - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/kkHAIKE/contextcheck/Makefile b/vendor/github.com/kkHAIKE/contextcheck/Makefile deleted file mode 100644 index 613d35e93..000000000 --- a/vendor/github.com/kkHAIKE/contextcheck/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: clean test build - -default: test build - -clean: - rm -rf dist/ cover.out - -test: clean - go test -v -cover ./... - -build: - go build -ldflags '-s -w' -o contextcheck ./cmd/contextcheck/main.go - -install: - go install -ldflags '-s -w' ./cmd/contextcheck diff --git a/vendor/github.com/kkHAIKE/contextcheck/README.md b/vendor/github.com/kkHAIKE/contextcheck/README.md deleted file mode 100644 index 105b2de5a..000000000 --- a/vendor/github.com/kkHAIKE/contextcheck/README.md +++ /dev/null @@ -1,157 +0,0 @@ -[![CircleCI](https://circleci.com/gh/sylvia7788/contextcheck.svg?style=svg)](https://circleci.com/gh/sylvia7788/contextcheck) - - -# contextcheck - -`contextcheck` is a static analysis tool used to check whether a function uses a non-inherited context that could result in a broken call link. - -For example: - -```go -func call1(ctx context.Context) { - ... - - ctx = getNewCtx(ctx) - call2(ctx) // OK - - call2(context.Background()) // Non-inherited new context, use function like `context.WithXXX` instead - - call3() // Function `call3` should pass the context parameter - call4() // Function `call4->call3` should pass the context parameter - ... -} - -func call2(ctx context.Context) { - ... -} - -func call3() { - ctx := context.TODO() - call2(ctx) -} - -func call4() { - call3() -} - - -// if you want none-inherit ctx, use this function -func getNewCtx(ctx context.Context) (newCtx context.Context) { - ... - return -} - -/* ---------- check net/http.HandleFunc ---------- */ - -func call5(ctx context.Context, w http.ResponseWriter, r *http.Request) { -} - -func call6(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - call5(ctx, w, r) - call5(context.Background(), w, r) // Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead -} - -func call7(in bool, w http.ResponseWriter, r *http.Request) { - call5(r.Context(), w, r) - call5(context.Background(), w, r) -} - -func call8() { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - call5(r.Context(), w, r) - call5(context.Background(), w, r) // Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead - - call6(w, r) - - // call7 should be like `func call7(ctx context.Context, in bool, w http.ResponseWriter, r *http.Request)` - call7(true, w, r) // Function `call7` should pass the context parameter - }) -} -``` - -## Tips -### need break ctx inheritance -eg: [issue](https://github.com/kkHAIKE/contextcheck/issues/2). - -```go -func call1(ctx context.Context) { - ... - - newCtx, cancel := NoInheritCancel(ctx) - defer cancel() - - call2(newCtx) - ... -} - -func call2(ctx context.Context) { - ... -} - -func NoInheritCancel(_ context.Context) (context.Context,context.CancelFunc) { - return context.WithCancel(context.Background()) -} -``` - -### skip the check for the specified function -To skip this linter in some false-positive cases, you can add // nolint: contextcheck to the function declaration's comment. - -```go -// nolint: contextcheck -func call1() { - doSomeThing(context.Background()) // add nolint will no issuss for that -} - -func call2(ctx context.Context) { - call1() -} - -func call3() { - call2(context.Background()) -} -``` - -### force the marking of a specified function as having a server-side http.Request parameter -The default behavior is to mark `http.HandlerFunc` or any function that uses `r.Context()`. - -```go -// @contextcheck(req_has_ctx) -func writeErr(w http.ResponseWriter, r *http.Request, err error) { - doSomeThing(r.Context()) -} - -func handler(w http.ResponseWriter, r *http.Request) { - ... - if err != nil { - writeErr(w, r, err) - return - } - ... -} -``` - -## Installation - -You can get `contextcheck` by `go get` command. - -```bash -$ go get -u github.com/kkHAIKE/contextcheck -``` - -or build yourself. - -```bash -$ make build -$ make install -``` - -## Usage - -Invoke `contextcheck` with your package name - -```bash -$ contextcheck ./... -$ # or -$ go vet -vettool=`which contextcheck` ./... -``` diff --git a/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go b/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go deleted file mode 100644 index 62696351a..000000000 --- a/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go +++ /dev/null @@ -1,825 +0,0 @@ -package contextcheck - -import ( - "go/ast" - "go/token" - "go/types" - "regexp" - "strings" - "sync" - - "github.com/gostaticanalysis/analysisutil" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/buildssa" - "golang.org/x/tools/go/packages" - "golang.org/x/tools/go/ssa" -) - -type Configuration struct { - DisableFact bool -} - -var pkgprefix string - -func NewAnalyzer(cfg Configuration) *analysis.Analyzer { - analyzer := &analysis.Analyzer{ - Name: "contextcheck", - Doc: "check whether the function uses a non-inherited context", - Run: NewRun(nil, cfg.DisableFact), - Requires: []*analysis.Analyzer{ - buildssa.Analyzer, - }, - } - analyzer.Flags.StringVar(&pkgprefix, "pkgprefix", "", "filter init pkgs (only for cmd)") - - if !cfg.DisableFact { - analyzer.FactTypes = append(analyzer.FactTypes, (*ctxFact)(nil)) - } - - return analyzer -} - -const ( - ctxPkg = "context" - ctxName = "Context" - - httpPkg = "net/http" - httpRes = "ResponseWriter" - httpReq = "Request" -) - -const ( - CtxIn int = 1 << iota // ctx in function's param - CtxOut // ctx in function's results - CtxInField // ctx in function's field param -) - -type entryType int - -const ( - EntryNone entryType = iota - EntryNormal // without ctx in - EntryWithCtx // has ctx in - EntryWithHttpHandler // is http handler -) - -var ( - pkgFactMap = make(map[*types.Package]ctxFact) - pkgFactMu sync.RWMutex -) - -type element interface { - Pos() token.Pos - Parent() *ssa.Function -} - -type resInfo struct { - Valid bool - Funcs []string - - // reuse for doc - ReqCtx bool - Skip bool - - EntryType entryType -} - -type ctxFact map[string]resInfo - -func (*ctxFact) String() string { return "ctxCheck" } -func (*ctxFact) AFact() {} - -type runner struct { - pass *analysis.Pass - ctxTyp *types.Named - ctxPTyp *types.Pointer - skipFile map[*ast.File]bool - - httpResTyps []types.Type - httpReqTyps []types.Type - - currentFact ctxFact - disableFact bool -} - -func getPkgRoot(pkg string) string { - arr := strings.Split(pkg, "/") - if len(arr) < 3 { - return arr[0] - } - if strings.IndexByte(arr[0], '.') == -1 { - return arr[0] - } - return strings.Join(arr[:3], "/") -} - -func NewRun(pkgs []*packages.Package, disableFact bool) func(pass *analysis.Pass) (interface{}, error) { - m := make(map[string]bool) - for _, pkg := range pkgs { - m[getPkgRoot(pkg.PkgPath)] = true - } - return func(pass *analysis.Pass) (interface{}, error) { - // skip different repo - if len(m) > 0 && !m[getPkgRoot(pass.Pkg.Path())] { - return nil, nil - } - if len(m) == 0 && pkgprefix != "" && !strings.HasPrefix(pass.Pkg.Path(), pkgprefix) { - return nil, nil - } - - r := &runner{disableFact: disableFact} - r.run(pass) - return nil, nil - } -} - -func (r *runner) run(pass *analysis.Pass) { - r.pass = pass - pssa := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) - funcs := pssa.SrcFuncs - - // collect ctx obj - var ok bool - r.ctxTyp, r.ctxPTyp, ok = r.getRequiedType(pssa, ctxPkg, ctxName) - if !ok { - return - } - - // collect http obj - r.collectHttpTyps(pssa) - - r.skipFile = make(map[*ast.File]bool) - r.currentFact = make(ctxFact) - - type entryInfo struct { - f *ssa.Function // entryfunc - tp entryType // entrytype - } - var tmpFuncs []entryInfo - for _, f := range funcs { - // skip checked function - key := f.RelString(nil) - if _, ok := r.currentFact[key]; ok { - continue - } - - if entryType := r.checkIsEntry(f); entryType == EntryNormal { - if _, ok := r.getValue(key, f); ok { - continue - } - // record the result of nomal function - checkingMap := make(map[string]bool) - checkingMap[key] = true - r.setFact(key, r.checkFuncWithoutCtx(f, checkingMap), f.Name()) - continue - } else if entryType == EntryWithCtx || entryType == EntryWithHttpHandler { - tmpFuncs = append(tmpFuncs, entryInfo{f: f, tp: entryType}) - } - } - - for _, v := range tmpFuncs { - r.checkFuncWithCtx(v.f, v.tp) - } - - if len(r.currentFact) > 0 { - if r.disableFact { - setPkgFact(pass.Pkg, r.currentFact) - } else { - pass.ExportPackageFact(&r.currentFact) - } - } -} - -func (r *runner) getRequiedType(pssa *buildssa.SSA, path, name string) (obj *types.Named, pobj *types.Pointer, ok bool) { - pkg := pssa.Pkg.Prog.ImportedPackage(path) - if pkg == nil { - return - } - - objTyp := pkg.Type(name) - if objTyp == nil { - return - } - obj, ok = objTyp.Object().Type().(*types.Named) - if !ok { - return - } - pobj = types.NewPointer(obj) - - return -} - -func (r *runner) collectHttpTyps(pssa *buildssa.SSA) { - objRes, _, ok := r.getRequiedType(pssa, httpPkg, httpRes) - if ok { - r.httpResTyps = append(r.httpResTyps, objRes) - } - - _, pobjReq, ok := r.getRequiedType(pssa, httpPkg, httpReq) - if ok { - r.httpReqTyps = append(r.httpReqTyps, pobjReq) - } -} - -func (r *runner) checkIsEntry(f *ssa.Function) (ret entryType) { - // if r.noImportedContextAndHttp(f) { - // return EntryNormal - // } - key := "entry:" + f.RelString(nil) - res, ok := r.getValue(key, f) - if ok { - return res.EntryType - } - defer func() { - r.currentFact[key] = resInfo{EntryType: ret} - }() - - ctxIn, ctxOut := r.checkIsCtx(f) - if ctxOut { - // skip the function which generate ctx - return EntryNone - } else if ctxIn { - // has ctx in, ignore *http.Request.Context() - return EntryWithCtx - } - - reqctx, skip := r.docFlag(f) - - // check is `func handler(w http.ResponseWriter, r *http.Request) {}` - // or use '// @contextcheck(req_has_ctx)' - if r.checkIsHttpHandler(f, reqctx) { - return EntryWithHttpHandler - } - - if skip { - return EntryNone - } - - return EntryNormal -} - -func (r *runner) docFlag(f *ssa.Function) (reqctx, skip bool) { - for _, v := range r.getDocFromFunc(f) { - if len(nolintRe.FindString(v.Text)) > 0 && strings.Contains(v.Text, "contextcheck") { - skip = true - } else if strings.HasPrefix(v.Text, "// @contextcheck(req_has_ctx)") { - reqctx = true - } - } - return -} - -var nolintRe = regexp.MustCompile(`^//\s?nolint:`) - -func (r *runner) getDocFromFunc(f *ssa.Function) []*ast.Comment { - file := analysisutil.File(r.pass, f.Pos()) - if file == nil { - return nil - } - - // only support FuncDecl comment - var fd *ast.FuncDecl - for _, v := range file.Decls { - if tmp, ok := v.(*ast.FuncDecl); ok && tmp.Name.Pos() == f.Pos() { - fd = tmp - break - } - } - if fd == nil || fd.Doc == nil || len(fd.Doc.List) == 0 { - return nil - } - return fd.Doc.List -} - -func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) { - // check params - tuple := f.Signature.Params() - for i := 0; i < tuple.Len(); i++ { - if r.isCtxType(tuple.At(i).Type()) { - in = true - break - } - } - - // check freevars - for _, param := range f.FreeVars { - if r.isCtxType(param.Type()) { - in = true - break - } - } - - // check results - tuple = f.Signature.Results() - for i := 0; i < tuple.Len(); i++ { - if r.isCtxType(tuple.At(i).Type()) { - out = true - break - } - } - return -} - -func (r *runner) checkIsHttpHandler(f *ssa.Function, reqctx bool) bool { - var hasReq bool - tuple := f.Signature.Params() - for i := 0; i < tuple.Len(); i++ { - if r.isHttpReqType(tuple.At(i).Type()) { - hasReq = true - break - } - } - if !hasReq { - return false - } - if reqctx { - return true - } - - // must be `func f(w http.ResponseWriter, r *http.Request) {}` - if f.Signature.Results().Len() == 0 && tuple.Len() == 2 && - r.isHttpResType(tuple.At(0).Type()) && r.isHttpReqType(tuple.At(1).Type()) { - return true - } - - // check if use r.Context() - return f.Blocks != nil && len(r.getHttpReqCtx(f, true)) > 0 -} - -func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[ssa.Instruction]bool, ok bool) { - ok = true - refMap = make(map[ssa.Instruction]bool) - checkedRefMap := make(map[ssa.Value]bool) - storeInstrs := make(map[*ssa.Store]bool) - phiInstrs := make(map[*ssa.Phi]bool) - - var checkRefs func(val ssa.Value, fromAddr bool) - var checkInstr func(instr ssa.Instruction, fromAddr bool) - - checkRefs = func(val ssa.Value, fromAddr bool) { - if val == nil || val.Referrers() == nil { - return - } - - if checkedRefMap[val] { - return - } - checkedRefMap[val] = true - - for _, instr := range *val.Referrers() { - checkInstr(instr, fromAddr) - } - } - - checkInstr = func(instr ssa.Instruction, fromAddr bool) { - switch i := instr.(type) { - case ssa.CallInstruction: - refMap[i] = true - tp := r.getCallInstrCtxType(i) - if tp&CtxOut != 0 { - // collect referrers of the results - checkRefs(i.Value(), false) - return - } - case *ssa.Store: - if fromAddr { - // collect all store to judge whether it's right value is valid - storeInstrs[i] = true - } else { - checkRefs(i.Addr, true) - } - case *ssa.UnOp: - checkRefs(i, false) - case *ssa.MakeClosure: - for _, param := range i.Bindings { - if r.isCtxType(param.Type()) { - refMap[i] = true - break - } - } - case *ssa.Extract: - // only care about ctx - if r.isCtxType(i.Type()) { - checkRefs(i, false) - } - case *ssa.Phi: - phiInstrs[i] = true - checkRefs(i, false) - case *ssa.TypeAssert: - // ctx.(*bm.Context) - } - } - - if isHttpHandler { - for _, v := range r.getHttpReqCtx(f, false) { - checkRefs(v, false) - } - } else { - for _, param := range f.Params { - if r.isCtxType(param.Type()) { - checkRefs(param, false) - } - } - - for _, param := range f.FreeVars { - if r.isCtxType(param.Type()) { - checkRefs(param, false) - } - } - } - - for instr := range storeInstrs { - if !checkedRefMap[instr.Val] { - r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead") - ok = false - } - } - - for instr := range phiInstrs { - for _, v := range instr.Edges { - if !checkedRefMap[v] { - r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead") - ok = false - } - } - } - - return -} - -func (r *runner) getHttpReqCtx(f *ssa.Function, least1 bool) (rets []ssa.Value) { - checkedRefMap := make(map[ssa.Value]bool) - - var checkRefs func(val ssa.Value, fromAddr bool) - var checkInstr func(instr ssa.Instruction, fromAddr bool) - - checkRefs = func(val ssa.Value, fromAddr bool) { - if val == nil || val.Referrers() == nil { - return - } - - if checkedRefMap[val] { - return - } - checkedRefMap[val] = true - - for _, instr := range *val.Referrers() { - checkInstr(instr, fromAddr) - } - } - - checkInstr = func(instr ssa.Instruction, fromAddr bool) { - switch i := instr.(type) { - case ssa.CallInstruction: - // r.Context() only has one recv - if len(i.Common().Args) != 1 { - break - } - - // find r.Context() - if r.getCallInstrCtxType(i)&CtxOut != CtxOut { - break - } - - // check is r.Context - f := r.getFunction(instr) - if f == nil || f.Name() != ctxName { - break - } - if f.Signature.Recv() != nil { - // collect the return of r.Context - rets = append(rets, i.Value()) - if least1 { - return - } - } - case *ssa.Store: - if !fromAddr { - checkRefs(i.Addr, true) - } - case *ssa.UnOp: - checkRefs(i, false) - case *ssa.Phi: - checkRefs(i, false) - case *ssa.MakeClosure: - case *ssa.Extract: - // http.Request can only be input - } - } - - for _, param := range f.Params { - if r.isHttpReqType(param.Type()) { - checkRefs(param, false) - } - } - - return -} - -func (r *runner) checkFuncWithCtx(f *ssa.Function, tp entryType) { - isHttpHandler := tp == EntryWithHttpHandler - refMap, ok := r.collectCtxRef(f, isHttpHandler) - if !ok { - return - } - - for _, b := range f.Blocks { - for _, instr := range b.Instrs { - tp, ok := r.getCtxType(instr) - if !ok { - continue - } - - // checked in collectCtxRef, skipped - if tp&CtxOut != 0 { - continue - } - - if tp&CtxIn != 0 { - if !refMap[instr] { - if isHttpHandler { - r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead") - } else { - r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead") - } - } - } - - ff := r.getFunction(instr) - if ff == nil { - continue - } - - key := ff.RelString(nil) - res, ok := r.getValue(key, ff) - if ok && !res.Valid { - if instr.Pos().IsValid() { - r.Reportf(instr, "Function `%s` should pass the context parameter", strings.Join(reverse(res.Funcs), "->")) - } else { - r.Reportf(ff, "Function `%s` should pass the context parameter", strings.Join(reverse(res.Funcs), "->")) - } - } - } - } -} - -func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]bool) (ret bool) { - ret = true - orgKey := f.RelString(nil) - var seted bool - for _, b := range f.Blocks { - for _, instr := range b.Instrs { - tp, ok := r.getCtxType(instr) - if !ok { - continue - } - - if tp&CtxOut != 0 { - continue - } - - // it is considered illegal as long as ctx is in the input and not in *struct X - if tp&CtxIn != 0 { - if tp&CtxInField == 0 { - ret = false - } - } - - ff := r.getFunction(instr) - if ff == nil { - continue - } - - key := ff.RelString(nil) - res, ok := r.getValue(key, ff) - if ok { - if !res.Valid { - ret = false - - // save the call link - if !seted { - seted = true - r.setFact(orgKey, res.Valid, res.Funcs...) - } - } - continue - } - - // check is thunk or bound - if strings.HasSuffix(key, "$thunk") || strings.HasSuffix(key, "$bound") { - continue - } - - if entryType := r.checkIsEntry(ff); entryType == EntryNormal { - // cannot get info from fact, skip - if ff.Blocks == nil { - continue - } - - // handler cycle call - if checkingMap[key] { - continue - } - checkingMap[key] = true - - valid := r.checkFuncWithoutCtx(ff, checkingMap) - r.setFact(key, valid, ff.Name()) - if res, ok := r.getValue(key, ff); ok && !valid && !seted { - seted = true - r.setFact(orgKey, valid, res.Funcs...) - } - if !valid { - ret = false - } - } - } - } - return ret -} - -func (r *runner) getCtxType(instr ssa.Instruction) (tp int, ok bool) { - switch i := instr.(type) { - case ssa.CallInstruction: - tp = r.getCallInstrCtxType(i) - ok = true - case *ssa.MakeClosure: - tp = r.getMakeClosureCtxType(i) - ok = true - } - return -} - -func (r *runner) getCallInstrCtxType(c ssa.CallInstruction) (tp int) { - // check params - for _, v := range c.Common().Args { - if r.isCtxType(v.Type()) { - if vv, ok := v.(*ssa.UnOp); ok { - if _, ok := vv.X.(*ssa.FieldAddr); ok { - tp |= CtxInField - } - } - - tp |= CtxIn - break - } - } - - // check results - if v := c.Value(); v != nil { - if r.isCtxType(v.Type()) { - tp |= CtxOut - } else { - tuple, ok := v.Type().(*types.Tuple) - if !ok { - return - } - for i := 0; i < tuple.Len(); i++ { - if r.isCtxType(tuple.At(i).Type()) { - tp |= CtxOut - break - } - } - } - } - - return -} - -func (r *runner) getMakeClosureCtxType(c *ssa.MakeClosure) (tp int) { - for _, v := range c.Bindings { - if r.isCtxType(v.Type()) { - if vv, ok := v.(*ssa.UnOp); ok { - if _, ok := vv.X.(*ssa.FieldAddr); ok { - tp |= CtxInField - } - } - - tp |= CtxIn - break - } - } - return -} - -func (r *runner) getFunction(instr ssa.Instruction) (f *ssa.Function) { - switch i := instr.(type) { - case ssa.CallInstruction: - if i.Common().IsInvoke() { - return - } - - switch c := i.Common().Value.(type) { - case *ssa.Function: - f = c - case *ssa.MakeClosure: - // captured in the outer layer - case *ssa.Builtin, *ssa.UnOp, *ssa.Lookup, *ssa.Phi: - // skipped - case *ssa.Extract, *ssa.Call: - // function is a result of a call, skipped - case *ssa.Parameter: - // function is a param, skipped - } - case *ssa.MakeClosure: - f = i.Fn.(*ssa.Function) - } - return -} - -func (r *runner) isCtxType(tp types.Type) bool { - return types.Identical(tp, r.ctxTyp) || types.Identical(tp, r.ctxPTyp) -} - -func (r *runner) isHttpResType(tp types.Type) bool { - for _, v := range r.httpResTyps { - if ok := types.Identical(v, v); ok { - return true - } - } - return false -} - -func (r *runner) isHttpReqType(tp types.Type) bool { - for _, v := range r.httpReqTyps { - if ok := types.Identical(tp, v); ok { - return true - } - } - return false -} - -func (r *runner) getValue(key string, f *ssa.Function) (res resInfo, ok bool) { - res, ok = r.currentFact[key] - if ok { - return - } - - if f.Pkg == nil { - return - } - - var fact ctxFact - var got bool - if r.disableFact { - fact, got = getPkgFact(f.Pkg.Pkg) - } else { - got = r.pass.ImportPackageFact(f.Pkg.Pkg, &fact) - } - if got { - res, ok = fact[key] - } - return -} - -func (r *runner) setFact(key string, valid bool, funcs ...string) { - var names []string - if !valid { - names = append(r.currentFact[key].Funcs, funcs...) - } - r.currentFact[key] = resInfo{ - Valid: valid, - Funcs: names, - } -} - -func (r *runner) Reportf(instr element, format string, args ...interface{}) { - pos := instr.Pos() - - if !pos.IsValid() && instr.Parent() != nil { - pos = instr.Parent().Pos() - } - - if !pos.IsValid() { - return - } - - r.pass.Reportf(pos, format, args...) -} - -// setPkgFact save fact to mem -func setPkgFact(pkg *types.Package, fact ctxFact) { - pkgFactMu.Lock() - pkgFactMap[pkg] = fact - pkgFactMu.Unlock() -} - -// getPkgFact get fact from mem -func getPkgFact(pkg *types.Package) (fact ctxFact, ok bool) { - pkgFactMu.RLock() - fact, ok = pkgFactMap[pkg] - pkgFactMu.RUnlock() - return -} - -func reverse(arr1 []string) (arr2 []string) { - l := len(arr1) - if l == 0 { - return - } - arr2 = make([]string, l) - for i := 0; i <= l/2; i++ { - arr2[i] = arr1[l-1-i] - arr2[l-1-i] = arr1[i] - } - return -} -- cgit mrf-deployment