diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/dvyukov | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/dvyukov')
12 files changed, 0 insertions, 2490 deletions
diff --git a/vendor/github.com/dvyukov/go-fuzz/LICENSE b/vendor/github.com/dvyukov/go-fuzz/LICENSE deleted file mode 100644 index dd5b3a58a..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/LICENSE +++ /dev/null @@ -1,174 +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. diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go deleted file mode 100644 index edafad179..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go +++ /dev/null @@ -1,908 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -package main - -import ( - "bytes" - "crypto/sha1" - "fmt" - "go/ast" - "go/constant" - "go/printer" - "go/token" - "go/types" - "io" - "strconv" - "strings" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" - . "github.com/dvyukov/go-fuzz/internal/go-fuzz-types" -) - -const fuzzdepPkg = "_go_fuzz_dep_" - -func instrument(pkg, fullName string, fset *token.FileSet, parsedFile *ast.File, info *types.Info, out io.Writer, blocks *[]CoverBlock, sonar *[]CoverBlock) { - file := &File{ - fset: fset, - pkg: pkg, - fullName: fullName, - astFile: parsedFile, - blocks: blocks, - info: info, - } - if sonar == nil { - file.addImport("go-fuzz-dep", fuzzdepPkg, "CoverTab") - ast.Walk(file, file.astFile) - } else { - s := &Sonar{ - fset: fset, - fullName: fullName, - pkg: pkg, - blocks: sonar, - info: info, - } - ast.Walk(s, file.astFile) - } - - file.print(out) -} - -type Sonar struct { - fset *token.FileSet - fullName string - pkg string - blocks *[]CoverBlock - info *types.Info -} - -var sonarSeq = 0 - -func (s *Sonar) Visit(n ast.Node) ast.Visitor { - // TODO: detect "x&mask==0", emit sonar(x, x&^mask) - switch nn := n.(type) { - case *ast.BinaryExpr: - break - - case *ast.GenDecl: - if nn.Tok != token.VAR { - return nil // constants and types are not interesting - } - return s - - case *ast.SelectorExpr: - return nil - - case *ast.SwitchStmt: - if nn.Tag == nil || nn.Body == nil { - return s // recurse - } - // Replace: - // switch a := foo(); bar(a) { - // case x: ... - // case y: ... - // } - // with: - // switch { - // default: - // a := foo() - // __tmp := bar(a) - // switch { - // case __tmp == x: ... - // case __tmp == y: ... - // } - // } - // The == comparisons will be instrumented later when we recurse. - sw := new(ast.SwitchStmt) - *sw = *nn - var stmts []ast.Stmt - if sw.Init != nil { - stmts = append(stmts, sw.Init) - sw.Init = nil - } - const tmpvar = "__go_fuzz_tmp" - tmp := ast.NewIdent(tmpvar) - typ := s.info.Types[sw.Tag] - s.info.Types[tmp] = typ - stmts = append(stmts, &ast.AssignStmt{Lhs: []ast.Expr{tmp}, Tok: token.DEFINE, Rhs: []ast.Expr{sw.Tag}}) - stmts = append(stmts, &ast.AssignStmt{Lhs: []ast.Expr{ast.NewIdent("_")}, Tok: token.ASSIGN, Rhs: []ast.Expr{tmp}}) - sw.Tag = nil - stmts = append(stmts, sw) - for _, cas1 := range sw.Body.List { - cas := cas1.(*ast.CaseClause) - for i, expr := range cas.List { - tmp := &ast.Ident{Name: tmpvar, NamePos: expr.Pos()} - s.info.Types[tmp] = typ - cas.List[i] = &ast.BinaryExpr{X: tmp, Op: token.EQL, Y: expr} - } - } - nn.Tag = nil - nn.Init = nil - nn.Body = &ast.BlockStmt{List: []ast.Stmt{&ast.CaseClause{Body: stmts}}} - return s // recurse - - case *ast.ForStmt: - // For condition is usually uninteresting, but produces lots of samples. - // So we skip it if it looks boring. - if nn.Init != nil { - ast.Walk(s, nn.Init) - } - if nn.Post != nil { - ast.Walk(s, nn.Post) - } - ast.Walk(s, nn.Body) - if nn.Cond != nil { - // Look for the following pattern: - // for foo := ...; foo ? ...; ... { ... } - boring := false - if nn.Init != nil { - if init, ok1 := nn.Init.(*ast.AssignStmt); ok1 && init.Tok == token.DEFINE && len(init.Lhs) == 1 { - if id, ok2 := init.Lhs[0].(*ast.Ident); ok2 { - if bex, ok3 := nn.Cond.(*ast.BinaryExpr); ok3 { - if x, ok4 := bex.X.(*ast.Ident); ok4 && x.Name == id.Name { - boring = true - } - if x, ok4 := bex.Y.(*ast.Ident); ok4 && x.Name == id.Name { - boring = true - } - } - } - } - } - if !boring { - ast.Walk(s, nn.Cond) - } - } - return nil - - default: - return s // recurse - } - - // TODO: handle map index expressions (especially useful for strings). - // E.g. when code matches a read in identifier against a set of known identifiers. - // For the record, it looks as follows. However, it is tricky to distinguish - // from slice/array index and map assignments... - //. . . . . . . *ast.IndexExpr { - //. . . . . . . . X: *ast.Ident { - //. . . . . . . . . Name: "m" - //. . . . . . . . } - //. . . . . . . . Index: *ast.Ident { - //. . . . . . . . . Name: "s" - //. . . . . . . . } - //. . . . . . . } - - // TODO: transform expressions so that lhs expression contains a variable - // and rhs contains all constant operands. For example, for (real code from vp8 codec): - // cf := (b[0]>>4)&7 == 5 - // we would like to transform it to: - // b[0] & (7<<4) == 5<<4 - // and then to: - // b[0] == 5<<4 | b & ^(7<<4) - // and emit: - // Sonar(b[0], 5<<4 | b & ^(7<<4), SonarEQL) - // This will allow the fuzzer to figure out what bytes it needs to replace - // with what bytes in order to crack this condition. - // Similarly, for: - // x/3 == 100 - // we would like to emit: - // Sonar(x, 100*3, SonarEQL) - - // TODO: intercept strings.Index/HasPrefix and similar functions. - - nn := n.(*ast.BinaryExpr) - var flags uint8 - switch nn.Op { - case token.EQL: - flags = SonarEQL - break - case token.NEQ: - flags = SonarNEQ - break - case token.LSS: - flags = SonarLSS - break - case token.GTR: - flags = SonarGTR - break - case token.LEQ: - flags = SonarLEQ - break - case token.GEQ: - flags = SonarGEQ - break - default: - return s // recurse - } - // Replace: - // x != y - // with: - // func() _go_fuzz_dep_.Bool { v1 := x; v2 := y; go-fuzz-dep.Sonar(v1, v2, flags); return v1 != v2 }() == true - // Using "== true" lets us modify the AST Node in-place. - v1 := nn.X - v2 := nn.Y - ast.Walk(s, v1) - ast.Walk(s, v2) - if isCap(v1) || isCap(v2) { - // Haven't seen useful cases yet. - return s - } - if isLen(v1) || isLen(v2) { - // TODO: we could pass both length value and the len argument. - // For example, if the code is: - // name := ... // obtained from input - // if len(name) > 5 { ... } - // If we would have the name value at runtime, we will know - // what part of the input to alter to affect len result. - flags |= SonarLength - } - - checkType := func(tv types.TypeAndValue) bool { - // Comparisons of pointers, maps, chans and bool are not interesting. - if _, ok := tv.Type.(*types.Pointer); ok { - return false - } - if _, ok := tv.Type.(*types.Map); ok { - return false - } - if _, ok := tv.Type.(*types.Chan); ok { - return false - } - s := tv.Type.Underlying().String() - if s == "bool" || s == "ideal bool" || s == "error" || - s == "untyped nil" || s == "unsafe.Pointer" { - return false - } - return true - } - if !checkType(s.info.Types[v1]) || !checkType(s.info.Types[v2]) { - return nil - } - var tv types.TypeAndValue - if isConstExpr(s.info, v1) { - flags |= SonarConst1 - } else { - tv = s.info.Types[v1] - } - if isConstExpr(s.info, v2) { - flags |= SonarConst2 - } else { - tv = s.info.Types[v2] - } - if flags&SonarConst1 != 0 && flags&SonarConst2 != 0 { - return nil - } - id := int(flags) | sonarSeq<<8 - startPos := s.fset.Position(nn.Pos()) - endPos := s.fset.Position(nn.End()) - *s.blocks = append(*s.blocks, CoverBlock{sonarSeq, s.fullName, startPos.Line, startPos.Column, endPos.Line, endPos.Column, int(flags)}) - sonarSeq++ - block := &ast.BlockStmt{} - - typstr := tv.Type.String() - if strings.HasPrefix(typstr, s.pkg+".") { - typstr = typstr[len(s.pkg)+1:] - } - if idx := strings.LastIndexByte(typstr, '/'); idx != -1 { - typstr = typstr[idx+1:] - } - conv := func(name string, v ast.Expr) ast.Expr { - // Convert const to the type of the other expr. - isConst := isConstExpr(s.info, v) - badConst := false - if isConst { - c := s.info.Types[v].Value - switch c.Kind() { - case constant.Int: - if v, ok := constant.Int64Val(c); !ok || int64(int(v)) != v { - // Such const can't be used outside of its current context, - // because it will be converted to int and that will fail. - badConst = true - } - case constant.Float: - badConst = true - } - } - if badConst || isWeirdShift(s.info, v) { - v = &ast.CallExpr{ - Fun: ast.NewIdent(typstr), - Args: []ast.Expr{v}, - } - s.info.Types[v] = tv - } - if !isConst { - // Assign to a temp to avoid double side-effects. - tmp := ast.NewIdent(name) - block.List = append(block.List, &ast.AssignStmt{Tok: token.DEFINE, Lhs: []ast.Expr{tmp}, Rhs: []ast.Expr{v}}) - v = tmp - s.info.Types[v] = tv - } - return v - } - v1 = conv("__gofuzz_v1", v1) - v2 = conv("__gofuzz_v2", v2) - - block.List = append(block.List, - &ast.ExprStmt{ - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: ast.NewIdent(fuzzdepPkg), Sel: ast.NewIdent("Sonar")}, - Args: []ast.Expr{v1, v2, &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(id)}}, - }, - }, - &ast.ReturnStmt{Results: []ast.Expr{&ast.BinaryExpr{Op: nn.Op, X: v1, Y: v2, OpPos: nn.Pos()}}}, - ) - nn.X = &ast.CallExpr{ - Fun: &ast.FuncLit{ - Type: &ast.FuncType{Results: &ast.FieldList{List: []*ast.Field{{Type: ast.NewIdent("_go_fuzz_dep_.Bool")}}}}, - Body: block, - }, - } - nn.Y = &ast.BasicLit{Kind: token.INT, Value: "true"} - nn.Op = token.EQL - return nil -} - -func isWeirdShift(info *types.Info, n ast.Expr) bool { - w := &WeirdShiftWalker{info: info} - ast.Walk(w, n) - return w.found -} - -type WeirdShiftWalker struct { - info *types.Info - found bool -} - -func (w *WeirdShiftWalker) Visit(n ast.Node) ast.Visitor { - if bin, ok := n.(*ast.BinaryExpr); ok && (bin.Op == token.SHL || bin.Op == token.SHR) && isConstExpr(w.info, bin.X) { - w.found = true - } - return w -} - -func isConstExpr(info *types.Info, n ast.Expr) bool { - tv := info.Types[n] - if tv.Type == nil && tv.Value == nil { - panic(fmt.Sprintf("untyped expression: %#v", n)) - } - return tv.Value != nil -} - -func isCap(n ast.Expr) bool { - if call, ok := n.(*ast.CallExpr); ok { - if id, ok2 := call.Fun.(*ast.Ident); ok2 { - return id.Name == "cap" - } - } - return false -} - -func isLen(n ast.Expr) bool { - if call, ok := n.(*ast.CallExpr); ok { - if id, ok2 := call.Fun.(*ast.Ident); ok2 { - return id.Name == "len" - } - } - return false -} - -type LiteralCollector struct { - ctxt *Context - lits map[Literal]struct{} -} - -func (lc *LiteralCollector) Visit(n ast.Node) (w ast.Visitor) { - switch nn := n.(type) { - default: - return lc // recurse - case *ast.ImportSpec: - return nil - case *ast.Field: - return nil // ignore field tags - case *ast.CallExpr: - switch fn := nn.Fun.(type) { - case *ast.Ident: - if fn.Name == "panic" { - return nil - } - case *ast.SelectorExpr: - if id, ok := fn.X.(*ast.Ident); ok && (id.Name == "fmt" || id.Name == "errors") { - return nil - } - } - return lc - case *ast.BasicLit: - lit := nn.Value - switch nn.Kind { - case token.STRING: - lc.lits[Literal{lc.unquote(lit), true}] = struct{}{} - case token.CHAR: - lc.lits[Literal{lc.unquote(lit), false}] = struct{}{} - case token.INT: - if lit[0] < '0' || lit[0] > '9' { - lc.ctxt.failf("unsupported literal '%v'", lit) - } - v, err := strconv.ParseInt(lit, 0, 64) - if err != nil { - u, err := strconv.ParseUint(lit, 0, 64) - if err != nil { - lc.ctxt.failf("failed to parse int literal '%v': %v", lit, err) - } - v = int64(u) - } - var val []byte - if v >= -(1<<7) && v < 1<<8 { - val = append(val, byte(v)) - } else if v >= -(1<<15) && v < 1<<16 { - val = append(val, byte(v), byte(v>>8)) - } else if v >= -(1<<31) && v < 1<<32 { - val = append(val, byte(v), byte(v>>8), byte(v>>16), byte(v>>24)) - } else { - val = append(val, byte(v), byte(v>>8), byte(v>>16), byte(v>>24), byte(v>>32), byte(v>>40), byte(v>>48), byte(v>>56)) - } - lc.lits[Literal{string(val), false}] = struct{}{} - } - return nil - } -} - -func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup { - var comments []*ast.CommentGroup - for _, group := range file.Comments { - var list []*ast.Comment - for _, comment := range group.List { - if strings.HasPrefix(comment.Text, "//go:") && !strings.HasPrefix(comment.Text, "//go:build") && fset.Position(comment.Slash).Column == 1 { - list = append(list, comment) - } - } - if list != nil { - comments = append(comments, &ast.CommentGroup{List: list}) - } - } - return comments -} - -func initialComments(content []byte) []byte { - // Derived from go/build.Context.shouldBuild. - end := 0 - p := content - for len(p) > 0 { - line := p - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, p = line[:i], p[i+1:] - } else { - p = p[len(p):] - } - line = bytes.TrimSpace(line) - if len(line) == 0 { // Blank line. - end = len(content) - len(p) - continue - } - if !bytes.HasPrefix(line, slashslash) { // Not comment line. - break - } - } - return content[:end] -} - -type File struct { - fset *token.FileSet - pkg string - fullName string - astFile *ast.File - blocks *[]CoverBlock - info *types.Info -} - -var slashslash = []byte("//") - -func (f *File) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.FuncDecl: - if n.Name.String() == "init" { - // Don't instrument init functions. - // They run regardless of what we do, so it is just noise. - return nil - } - case *ast.GenDecl: - if n.Tok != token.VAR { - return nil // constants and types are not interesting - } - - case *ast.BlockStmt: - // If it's a switch or select, the body is a list of case clauses; don't tag the block itself. - if len(n.List) > 0 { - switch n.List[0].(type) { - case *ast.CaseClause: // switch - for _, n := range n.List { - clause := n.(*ast.CaseClause) - clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false) - } - return f - case *ast.CommClause: // select - for _, n := range n.List { - clause := n.(*ast.CommClause) - clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false) - } - return f - } - } - n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace. - case *ast.IfStmt: - if n.Init != nil { - ast.Walk(f, n.Init) - } - if n.Cond != nil { - ast.Walk(f, n.Cond) - } - ast.Walk(f, n.Body) - if n.Else == nil { - // Add else because we want coverage for "not taken". - n.Else = &ast.BlockStmt{ - Lbrace: n.Body.End(), - Rbrace: n.Body.End(), - } - } - // The elses are special, because if we have - // if x { - // } else if y { - // } - // we want to cover the "if y". To do this, we need a place to drop the counter, - // so we add a hidden block: - // if x { - // } else { - // if y { - // } - // } - switch stmt := n.Else.(type) { - case *ast.IfStmt: - block := &ast.BlockStmt{ - Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else". - List: []ast.Stmt{stmt}, - Rbrace: stmt.End(), - } - n.Else = block - case *ast.BlockStmt: - stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else". - default: - panic("unexpected node type in if") - } - ast.Walk(f, n.Else) - return nil - case *ast.ForStmt: - // TODO: handle increment statement - case *ast.SelectStmt: - // Don't annotate an empty select - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.SwitchStmt: - hasDefault := false - if n.Body == nil { - n.Body = new(ast.BlockStmt) - } - for _, s := range n.Body.List { - if cas, ok := s.(*ast.CaseClause); ok && cas.List == nil { - hasDefault = true - break - } - } - if !hasDefault { - // Add default case to get additional coverage. - n.Body.List = append(n.Body.List, &ast.CaseClause{}) - } - - // Don't annotate an empty switch - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.TypeSwitchStmt: - // Don't annotate an empty type switch - creates a syntax error. - // TODO: add default case - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.BinaryExpr: - if n.Op == token.LAND || n.Op == token.LOR { - // Replace: - // x && y - // with: - // x && func() T { return y } - // where T is a bool of the same type as n (and x and y). - - // Spelling T correctly is a little tricky. - // go/types gives us a canonical name for T, - // but we can't always use that canonical name in the code directly; - // in the general case, it is of the form a/b/c/d.U. - // When U is the built-in bool, or defined in the current package, - // or defined in a dot-imported package, we want just U. - // When U is in another package, we want d.U. - // When U is in another package, imported under the name e, we want e.U. - // (And when the built-in bool type is shadowed, we're just screwed.) - // Handling all of these cases correctly is hard (it requires parsing the imports), - // so we handle just the common cases. - - // types.Default maps untyped bools to typed bools. - typ := types.Default(f.info.Types[n].Type).String() - // If we're in the current package, strip the package path. - if strings.HasPrefix(typ, f.pkg+".") { - typ = typ[len(f.pkg)+1:] - } - // If we're still in a package, assume it was imported with a reasonable name. - if i := strings.LastIndexByte(typ, '/'); i >= 0 { - typ = typ[i+1:] - } - - n.Y = &ast.CallExpr{ - Fun: &ast.FuncLit{ - Type: &ast.FuncType{Results: &ast.FieldList{List: []*ast.Field{{Type: ast.NewIdent(typ)}}}}, - Body: &ast.BlockStmt{List: []ast.Stmt{&ast.ReturnStmt{Results: []ast.Expr{n.Y}}}}, - }, - } - } - } - return f -} - -func (f *File) addImport(path, name, anyIdent string) { - newImport := &ast.ImportSpec{ - Name: ast.NewIdent(name), - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: fmt.Sprintf("%q", path), - }, - } - impDecl := &ast.GenDecl{ - Lparen: f.astFile.Name.End(), - Tok: token.IMPORT, - Specs: []ast.Spec{ - newImport, - }, - Rparen: f.astFile.Name.End(), - } - // Make the new import the first Decl in the file. - astFile := f.astFile - astFile.Decls = append(astFile.Decls, nil) - copy(astFile.Decls[1:], astFile.Decls[0:]) - astFile.Decls[0] = impDecl - astFile.Imports = append(astFile.Imports, newImport) - - // Now refer to the package, just in case it ends up unused. - // That is, append to the end of the file the declaration - // var _ = _cover_atomic_.AddUint32 - reference := &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{ - ast.NewIdent("_"), - }, - Values: []ast.Expr{ - &ast.SelectorExpr{ - X: ast.NewIdent(name), - Sel: ast.NewIdent(anyIdent), - }, - }, - }, - }, - } - astFile.Decls = append(astFile.Decls, reference) -} - -func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt { - // Special case: make sure we add a counter to an empty block. Can't do this below - // or we will add a counter to an empty statement list after, say, a return statement. - if len(list) == 0 { - return []ast.Stmt{f.newCounter(pos, blockEnd, 0)} - } - // We have a block (statement list), but it may have several basic blocks due to the - // appearance of statements that affect the flow of control. - var newList []ast.Stmt - for { - // Find first statement that affects flow of control (break, continue, if, etc.). - // It will be the last statement of this basic block. - var last int - end := blockEnd - for last = 0; last < len(list); last++ { - end = f.statementBoundary(list[last]) - if f.endsBasicSourceBlock(list[last]) { - extendToClosingBrace = false // Block is broken up now. - last++ - break - } - } - if extendToClosingBrace { - end = blockEnd - } - if pos != end { // Can have no source to cover if e.g. blocks abut. - newList = append(newList, f.newCounter(pos, end, last)) - } - newList = append(newList, list[0:last]...) - list = list[last:] - if len(list) == 0 { - break - } - pos = list[0].Pos() - } - return newList -} - -func (f *File) endsBasicSourceBlock(s ast.Stmt) bool { - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return true - case *ast.BranchStmt: - return true - case *ast.ForStmt: - return true - case *ast.IfStmt: - return true - case *ast.LabeledStmt: - return f.endsBasicSourceBlock(s.Stmt) - case *ast.RangeStmt: - return true - case *ast.SwitchStmt: - return true - case *ast.SelectStmt: - return true - case *ast.TypeSwitchStmt: - return true - case *ast.ExprStmt: - // Calls to panic change the flow. - // We really should verify that "panic" is the predefined function, - // but without type checking we can't and the likelihood of it being - // an actual problem is vanishingly small. - if call, ok := s.X.(*ast.CallExpr); ok { - if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 { - return true - } - } - } - found, _ := hasFuncLiteral(s) - return found -} - -func (f *File) statementBoundary(s ast.Stmt) token.Pos { - // Control flow statements are easy. - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return s.Lbrace - case *ast.IfStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - return s.Body.Lbrace - case *ast.ForStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Post) - if found { - return pos - } - return s.Body.Lbrace - case *ast.LabeledStmt: - return f.statementBoundary(s.Stmt) - case *ast.RangeStmt: - found, pos := hasFuncLiteral(s.X) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Tag) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SelectStmt: - return s.Body.Lbrace - case *ast.TypeSwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - return s.Body.Lbrace - } - found, pos := hasFuncLiteral(s) - if found { - return pos - } - return s.End() -} - -var counterGen uint32 - -func genCounter() int { - counterGen++ - id := counterGen - buf := []byte{byte(id), byte(id >> 8), byte(id >> 16), byte(id >> 24)} - hash := sha1.Sum(buf) - return int(uint16(hash[0]) | uint16(hash[1])<<8) -} - -func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt { - cnt := genCounter() - - if f.blocks != nil { - s := f.fset.Position(start) - e := f.fset.Position(end) - *f.blocks = append(*f.blocks, CoverBlock{cnt, f.fullName, s.Line, s.Column, e.Line, e.Column, numStmt}) - } - - idx := &ast.BasicLit{ - Kind: token.INT, - Value: strconv.Itoa(cnt), - } - counter := &ast.IndexExpr{ - X: &ast.SelectorExpr{ - X: ast.NewIdent(fuzzdepPkg), - Sel: ast.NewIdent("CoverTab"), - }, - Index: idx, - } - return &ast.IncDecStmt{ - X: counter, - Tok: token.INC, - } -} - -func (f *File) print(w io.Writer) { - cfg := printer.Config{ - Mode: printer.SourcePos, - Tabwidth: 8, - Indent: 0, - } - cfg.Fprint(w, f.fset, f.astFile) -} - -type funcLitFinder token.Pos - -func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) { - if f.found() { - return nil // Prune search. - } - switch n := node.(type) { - case *ast.FuncLit: - *f = funcLitFinder(n.Body.Lbrace) - return nil // Prune search. - } - return f -} - -func (f *funcLitFinder) found() bool { - return token.Pos(*f) != token.NoPos -} - -func hasFuncLiteral(n ast.Node) (bool, token.Pos) { - if n == nil { - return false, 0 - } - var literal funcLitFinder - ast.Walk(&literal, n) - return literal.found(), token.Pos(literal) -} - -func (lc *LiteralCollector) unquote(s string) string { - t, err := strconv.Unquote(s) - if err != nil { - lc.ctxt.failf("cover: improperly quoted string %q\n", s) - } - return t -} diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go deleted file mode 100644 index 91305ee37..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go +++ /dev/null @@ -1,904 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -package main - -import ( - "archive/zip" - "bytes" - "encoding/json" - "flag" - "fmt" - "go/ast" - "go/parser" - "go/token" - "go/types" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "runtime" - "runtime/pprof" - "strings" - "text/template" - "unicode" - "unicode/utf8" - - "golang.org/x/tools/go/packages" - - . "github.com/dvyukov/go-fuzz/internal/go-fuzz-types" -) - -var ( - flagTag = flag.String("tags", "", "a space-separated list of build tags to consider satisfied during the build") - flagOut = flag.String("o", "", "output file") - flagFunc = flag.String("func", "", "preferred entry function") - flagWork = flag.Bool("work", false, "don't remove working directory") - flagRace = flag.Bool("race", false, "enable race detector") - flagCPU = flag.Bool("cpuprofile", false, "generate cpu profile in cpu.pprof") - flagLibFuzzer = flag.Bool("libfuzzer", false, "output static archive for use with libFuzzer") - flagBuildX = flag.Bool("x", false, "print the commands if build fails") - flagPreserve = flag.String("preserve", "", "a comma-separated list of import paths not to instrument") - flagGoCmd = flag.String("go", "go", `path to "go" command`) -) - -func makeTags() string { - tags := "gofuzz" - if *flagLibFuzzer { - tags += " gofuzz_libfuzzer" - } - if *flagRace { - tags += " race" - } - if len(*flagTag) > 0 { - tags += " " + *flagTag - } - return tags -} - -// basePackagesConfig returns a base golang.org/x/tools/go/packages.Config -// that clients can then modify and use for calls to go/packages. -func basePackagesConfig() *packages.Config { - cfg := new(packages.Config) - - // Note that we do not set GO111MODULE here in order to respect any GO111MODULE - // setting by the user as we are finding dependencies. Note, however, that - // we are still setting up a GOPATH to build, so we later will force - // GO111MODULE to be off when building so that we are in GOPATH mode. - // If the user has not set GO111MODULE, the meaning here is - // left up to cmd/go (defaulting to 'auto' in Go 1.11-1.13, - // but likely defaulting to 'on' at some point during Go 1.14 - // development cycle). - // Also note that we are leaving the overall cfg structure - // in place to support future experimentation, etc. - cfg.Env = os.Environ() - return cfg -} - -// checkModVendor reports if the GOFLAGS env variable -// contains -mod=vendor, which enables vendoring for modules. -func checkModVendor() bool { - val := os.Getenv("GOFLAGS") - for _, s := range strings.Split(val, " ") { - if s == "-mod=vendor" { - return true - } - } - return false -} - -// main copies the package with all dependent packages into a temp dir, -// instruments Go source files there, and builds setting GOROOT to the temp dir. -func main() { - flag.Parse() - c := new(Context) - - if flag.NArg() > 1 { - c.failf("usage: go-fuzz-build [pkg]") - } - - pkg := "." - if flag.NArg() == 1 { - pkg = flag.Arg(0) - } - if *flagFunc != "" && !isFuzzFuncName(*flagFunc) { - c.failf("provided -func=%v, but %v is not a fuzz function name", *flagFunc, *flagFunc) - } - if *flagLibFuzzer && *flagRace { - c.failf("-race and -libfuzzer are incompatible") - } - if checkModVendor() { - // We don't support -mod=vendor with modules. - // Part of the issue is go-fuzz-dep and go-fuzz-defs - // won't be in the user's vendor directory. - c.failf("GOFLAGS with -mod=vendor is not supported") - } - - c.startProfiling() // start pprof as requested - c.loadPkg(pkg) // load and typecheck pkg - c.getEnv() // discover GOROOT, GOPATH - c.loadStd() // load standard library - c.calcIgnore() // calculate set of packages to ignore - c.makeWorkdir() // create workdir - defer c.cleanup() // delete workdir as needed, etc. - c.populateWorkdir() // copy tools and packages to workdir as needed - - if *flagOut == "" { - ext := ".zip" - if *flagLibFuzzer { - ext = ".a" - } - *flagOut = c.pkgs[0].Name + "-fuzz" + ext - } - - // Gather literals, instrument, and compile. - // Order matters here! - // buildInstrumentedBinary (and instrumentPackages) modify the AST. - // (We don't want to re-parse and re-typecheck every time, for performance.) - // So we gather literals first, while the AST is pristine. - // Then we add coverage and build. - // Then we add sonar and build. - // TODO: migrate to use cmd/internal/edit instead of AST modification. - // This has several benefits: (1) It is easier to work with. - // (2) 'go cover' has switched to it; we would get the benefit of - // upstream bug fixes, of which there has been at least one (around gotos and labels). - // (3) It leaves the AST intact, so we are less order-sensitive. - // The primary blocker is that we want good line numbers for when we find crashers. - // go/printer handles this automatically using Mode printer.SourcePos. - // We'd need to implement that support ourselves. (It's do-able but non-trivial.) - // See also https://golang.org/issue/29824. - lits := c.gatherLiterals() - var blocks, sonar []CoverBlock - - if *flagLibFuzzer { - archive := c.buildInstrumentedBinary(&blocks, nil) - c.moveFile(archive, *flagOut) - return - } - - coverBin := c.buildInstrumentedBinary(&blocks, nil) - sonarBin := c.buildInstrumentedBinary(nil, &sonar) - metaData := c.createMeta(lits, blocks, sonar) - defer func() { - os.Remove(coverBin) - os.Remove(sonarBin) - os.Remove(metaData) - }() - - outf, err := os.Create(*flagOut) - if err != nil { - c.failf("failed to create output file: %v", err) - } - zipw := zip.NewWriter(outf) - zipFile := func(name, datafile string) { - w, err := zipw.Create(name) - if err != nil { - c.failf("failed to create zip file: %v", err) - } - f, err := os.Open(datafile) - if err != nil { - c.failf("failed to open data file %v", datafile) - } - if _, err := io.Copy(w, f); err != nil { - c.failf("failed to write %v to zip file: %v", datafile, err) - } - // best effort: close and remove our temp file - f.Close() - os.Remove(datafile) - } - zipFile("cover.exe", coverBin) - zipFile("sonar.exe", sonarBin) - zipFile("metadata", metaData) - if err := zipw.Close(); err != nil { - c.failf("failed to close zip file: %v", err) - } - if err := outf.Close(); err != nil { - c.failf("failed to close out file: %v", err) - } -} - -// Context holds state for a go-fuzz-build run. -type Context struct { - fuzzpkg *packages.Package // package containing Fuzz function - pkgs []*packages.Package // typechecked root packages - - std map[string]bool // set of packages in the standard library - ignore map[string]bool // set of packages to ignore during instrumentation - - allFuncs []string // all fuzz functions found in package - - workdir string - GOROOT string - GOPATH string - - cpuprofile *os.File - - cmdGoHasTrimPath bool // does the active version of cmd/go have the -trimpath flag? -} - -// getEnv determines GOROOT and GOPATH and updates c accordingly. -func (c *Context) getEnv() { - env := map[string]string{ - "GOROOT": "", - "GOPATH": "", - } - for k := range env { - v := os.Getenv(k) - if v != "" { - env[k] = v - continue - } - // TODO: make a single call ("go env GOROOT GOPATH") instead - out, err := exec.Command(*flagGoCmd, "env", k).CombinedOutput() - if err != nil || len(out) == 0 { - c.failf("%s is not set and failed to locate it: 'go env %s' returned '%s' (%v)", k, k, out, err) - } - env[k] = strings.TrimSpace(string(out)) - } - c.GOROOT = env["GOROOT"] - c.GOPATH = env["GOPATH"] - - out, err := exec.Command(*flagGoCmd, "list", "-f", "'{{context.ReleaseTags}}'", "runtime").CombinedOutput() - if err != nil || len(out) == 0 { - c.failf("go list -f '{{context.ReleaseTags}}' runtime returned '%s' (%v)", out, err) - } - c.cmdGoHasTrimPath = bytes.Contains(out, []byte("go1.13")) -} - -// startProfiling starts pprof profiling, if requested. -func (c *Context) startProfiling() { - if !*flagCPU { - return - } - var err error - c.cpuprofile, err = os.Create("cpu.pprof") - if err != nil { - c.failf("could not create cpu profile: %v", err) - } - pprof.StartCPUProfile(c.cpuprofile) -} - -// loadPkg loads, parses, and typechecks pkg (the package containing the Fuzz function), -// go-fuzz-dep, and their dependencies. -func (c *Context) loadPkg(pkg string) { - // Resolve pkg. - // See https://golang.org/issue/30826 and https://golang.org/issue/30828. - rescfg := basePackagesConfig() - rescfg.Mode = packages.NeedName - rescfg.BuildFlags = []string{"-tags", makeTags()} - respkgs, err := packages.Load(rescfg, pkg) - if err != nil { - c.failf("could not resolve package %q: %v", pkg, err) - } - if len(respkgs) != 1 { - paths := make([]string, len(respkgs)) - for i, p := range respkgs { - paths[i] = p.PkgPath - } - c.failf("cannot build multiple packages, but %q resolved to: %v", pkg, strings.Join(paths, ", ")) - } - if respkgs[0].Name == "main" { - c.failf("cannot fuzz package main") - } - pkgpath := respkgs[0].PkgPath - - // Load, parse, and type-check all packages. - // We'll use the type information later. - // This also provides better error messages in the case - // of invalid code than trying to compile instrumented code. - cfg := basePackagesConfig() - cfg.Mode = packages.LoadAllSyntax - cfg.BuildFlags = []string{"-tags", makeTags()} - // use custom ParseFile in order to get comments - cfg.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { - return parser.ParseFile(fset, filename, src, parser.ParseComments) - } - // We need to load: - // * the target package, obviously - // * go-fuzz-dep, since we use it for instrumentation - // * reflect, if we are using libfuzzer, since its generated main function requires it - loadpkgs := []string{pkg, "github.com/dvyukov/go-fuzz/go-fuzz-dep"} - if *flagLibFuzzer { - loadpkgs = append(loadpkgs, "reflect") - } - initial, err := packages.Load(cfg, loadpkgs...) - if err != nil { - c.failf("could not load packages: %v", err) - } - - // Stop if any package had errors. - if packages.PrintErrors(initial) > 0 { - c.failf("typechecking of %v failed", pkg) - } - - c.pkgs = initial - - // Find the fuzz package among c.pkgs. - for _, p := range initial { - if p.PkgPath == pkgpath { - c.fuzzpkg = p - break - } - } - if c.fuzzpkg == nil { - c.failf("internal error: failed to find fuzz package; please file an issue") - } - - // Find all fuzz functions in fuzzpkg. - foundFlagFunc := false - s := c.fuzzpkg.Types.Scope() - for _, n := range s.Names() { - if !isFuzzFuncName(n) { - continue - } - // Check that n is a function with an appropriate signature. - typ := s.Lookup(n).Type() - sig, ok := typ.(*types.Signature) - if !ok || sig.Variadic() || !isFuzzSig(sig) { - if n == *flagFunc { - c.failf("provided -func=%v, but %v is not a fuzz function", *flagFunc, *flagFunc) - } - continue - } - // n is a fuzz function. - c.allFuncs = append(c.allFuncs, n) - foundFlagFunc = foundFlagFunc || n == *flagFunc - } - - if len(c.allFuncs) == 0 { - c.failf("could not find any fuzz functions in %v", c.fuzzpkg.PkgPath) - } - if len(c.allFuncs) > 255 { - c.failf("go-fuzz-build supports a maximum of 255 fuzz functions, found %v; please file an issue", len(c.allFuncs)) - } - - if *flagFunc != "" { - // Specific fuzz function requested. - // If the requested function doesn't exist, fail. - if !foundFlagFunc { - c.failf("could not find fuzz function %v in %v", *flagFunc, c.fuzzpkg.PkgPath) - } - } else { - // No specific fuzz function requested. - // If there's only one fuzz function, mark it as preferred. - // If there's more than one... - // ...for go-fuzz, that's fine; one can be specified later on the command line. - // ...for libfuzzer, that's not fine, as there is no way to specify one later. - if len(c.allFuncs) == 1 { - *flagFunc = c.allFuncs[0] - } else if *flagLibFuzzer { - c.failf("must specify a fuzz function with -libfuzzer, found: %v", strings.Join(c.allFuncs, ", ")) - } - } -} - -// isFuzzSig reports whether sig is of the form -// func FuzzFunc(data []byte) int -func isFuzzSig(sig *types.Signature) bool { - return tupleHasTypes(sig.Params(), "[]byte") && tupleHasTypes(sig.Results(), "int") -} - -// tupleHasTypes reports whether tuple is composed of -// elements with exactly the types in types. -func tupleHasTypes(tuple *types.Tuple, types ...string) bool { - if tuple.Len() != len(types) { - return false - } - for i, t := range types { - if tuple.At(i).Type().String() != t { - return false - } - } - return true -} - -func isFuzzFuncName(name string) bool { - return isTest(name, "Fuzz") -} - -// isTest is copied verbatim, along with its name, -// from GOROOT/src/cmd/go/internal/load/test.go. -// isTest tells whether name looks like a test (or benchmark, according to prefix). -// It is a Test (say) if there is a character after Test that is not a lower-case letter. -// We don't want TesticularCancer. -func isTest(name, prefix string) bool { - if !strings.HasPrefix(name, prefix) { - return false - } - if len(name) == len(prefix) { // "Test" is ok - return true - } - rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) - return !unicode.IsLower(rune) -} - -// loadStd finds the set of standard library package paths. -func (c *Context) loadStd() { - // Find out what packages are in the standard library. - cfg := basePackagesConfig() - cfg.Mode = packages.NeedName - stdpkgs, err := packages.Load(cfg, "std") - if err != nil { - c.failf("could not load standard library: %v", err) - } - c.std = make(map[string]bool, len(stdpkgs)) - for _, p := range stdpkgs { - c.std[p.PkgPath] = true - } -} - -// makeWorkdir creates the workdir, logging as requested. -func (c *Context) makeWorkdir() { - // TODO: make workdir stable, so that we can use cmd/go's build cache? - // See https://github.com/golang/go/issues/29430. - var err error - c.workdir, err = ioutil.TempDir("", "go-fuzz-build") - if err != nil { - c.failf("failed to create temp dir: %v", err) - } - if *flagWork { - fmt.Printf("workdir: %v\n", c.workdir) - } -} - -// cleanup ensures a clean exit. It should be called on all (controllable) exit paths. -func (c *Context) cleanup() { - if !*flagWork && c.workdir != "" { - os.RemoveAll(c.workdir) - } - if c.cpuprofile != nil { - pprof.StopCPUProfile() - c.cpuprofile.Close() - } -} - -// populateWorkdir prepares workdir for builds. -func (c *Context) populateWorkdir() { - // TODO: instead of reconstructing the world, - // can we use a bunch of replace directives in a go.mod? - - // TODO: make all this I/O concurrent (up to a limit). - // It's a non-trivial part of build time. - // Question: Do it here or in copyDir? - - // TODO: See if we can avoid making toolchain copies, - // using some combination of env vars and toolexec. - if *flagLibFuzzer || *flagRace { - c.copyDir(filepath.Join(c.GOROOT, "src", "runtime", "cgo"), filepath.Join(c.workdir, "goroot", "src", "runtime", "cgo")) - } - if *flagRace { - c.copyDir(filepath.Join(c.GOROOT, "src", "runtime", "race"), filepath.Join(c.workdir, "goroot", "src", "runtime", "race")) - c.copyDir(filepath.Join(c.GOROOT, "src", "sync", "atomic"), filepath.Join(c.workdir, "goroot", "src", "sync", "atomic")) - } - c.copyDir(filepath.Join(c.GOROOT, "pkg", "tool"), filepath.Join(c.workdir, "goroot", "pkg", "tool")) - if _, err := os.Stat(filepath.Join(c.GOROOT, "pkg", "include")); err == nil { - c.copyDir(filepath.Join(c.GOROOT, "pkg", "include"), filepath.Join(c.workdir, "goroot", "pkg", "include")) - } else { - // Cross-compilation is not implemented. - c.copyDir(filepath.Join(c.GOROOT, "pkg", runtime.GOOS+"_"+runtime.GOARCH), filepath.Join(c.workdir, "goroot", "pkg", runtime.GOOS+"_"+runtime.GOARCH)) - } - // go1.17 added abi_amd64.h - if _, err := os.Stat(filepath.Join(c.GOROOT, "src", "runtime", "cgo", "abi_amd64.h")); err == nil { - c.mkdirAll(filepath.Join(c.workdir, "goroot", "src", "runtime", "cgo")) - c.copyFile(filepath.Join(c.GOROOT, "src", "runtime", "cgo", "abi_amd64.h"), filepath.Join(c.workdir, "goroot", "src", "runtime", "cgo", "abi_amd64.h")) - } - - // Clone our package, go-fuzz-deps, and all dependencies. - // TODO: we might not need to do this for all packages. - // We know that we'll be writing out instrumented Go code later; - // we could instead just os.MkdirAll and copy non-Go files here. - // We'd still need to do a full package clone for packages that - // we aren't instrumenting (c.ignore). - packages.Visit(c.pkgs, nil, func(p *packages.Package) { - c.clonePackage(p) - }) - c.copyFuzzDep() -} - -func (c *Context) createMeta(lits map[Literal]struct{}, blocks []CoverBlock, sonar []CoverBlock) string { - meta := MetaData{Blocks: blocks, Sonar: sonar, Funcs: c.allFuncs, DefaultFunc: *flagFunc} - for k := range lits { - meta.Literals = append(meta.Literals, k) - } - data, err := json.Marshal(meta) - if err != nil { - c.failf("failed to serialize meta information: %v", err) - } - f := c.tempFile() - c.writeFile(f, data) - return f -} - -func (c *Context) buildInstrumentedBinary(blocks *[]CoverBlock, sonar *[]CoverBlock) string { - c.instrumentPackages(blocks, sonar) - mainPkg := c.createFuzzMain() - outf := c.tempFile() - args := []string{"build", "-tags", makeTags()} - if *flagBuildX { - args = append(args, "-x") - - if *flagWork { - args = append(args, "-work") - } - } - if *flagRace { - args = append(args, "-race") - } - if *flagLibFuzzer { - args = append(args, "-buildmode=c-archive") - } - if c.cmdGoHasTrimPath { - args = append(args, "-trimpath") - } - args = append(args, "-o", outf, mainPkg) - cmd := exec.Command(*flagGoCmd, args...) - - // We are constructing a GOPATH environment, so while building - // we force GOPATH mode here via GO111MODULE=off. - cmd.Env = append(os.Environ(), - "GOROOT="+filepath.Join(c.workdir, "goroot"), - "GOPATH="+filepath.Join(c.workdir, "gopath"), - "GO111MODULE=off", - ) - if out, err := cmd.CombinedOutput(); err != nil { - c.failf("failed to execute go build: %v\n%v", err, string(out)) - } - return outf -} - -func (c *Context) calcIgnore() { - // No reason to instrument these. - c.ignore = map[string]bool{ - "runtime/cgo": true, - "runtime/pprof": true, - "runtime/race": true, - } - - // Roots: must not instrument these, nor any of their dependencies, to avoid import cycles. - // Fortunately, these are mostly packages that are non-deterministic, - // noisy (because they are low level), and/or not interesting. - // We could manually maintain this list, but that makes go-fuzz-build - // fragile in the face of internal standard library package changes. - roots := c.packagesNamed("runtime", "github.com/dvyukov/go-fuzz/go-fuzz-dep") - packages.Visit(roots, func(p *packages.Package) bool { - c.ignore[p.PkgPath] = true - return true - }, nil) - - // Ignore any packages requested explicitly by the user. - paths := strings.Split(*flagPreserve, ",") - for _, path := range paths { - c.ignore[path] = true - } -} - -func (c *Context) gatherLiterals() map[Literal]struct{} { - nolits := map[string]bool{ - "math": true, - "os": true, - "unicode": true, - } - - lits := make(map[Literal]struct{}) - visit := func(pkg *packages.Package) { - if c.ignore[pkg.PkgPath] || nolits[pkg.PkgPath] { - return - } - for _, f := range pkg.Syntax { - ast.Walk(&LiteralCollector{lits: lits, ctxt: c}, f) - } - } - - packages.Visit(c.pkgs, nil, visit) - return lits -} - -func (c *Context) copyFuzzDep() { - // Standard library packages can't depend on non-standard ones. - // So we pretend that go-fuzz-dep is a standard one. - // go-fuzz-dep depends on go-fuzz-defs, which creates a problem. - // Fortunately (and intentionally), go-fuzz-defs contains only constants, - // which can be duplicated safely. - // So we eliminate the import statement and copy go-fuzz-defs/defs.go - // directly into the go-fuzz-dep package. - newDir := filepath.Join(c.workdir, "goroot", "src", "go-fuzz-dep") - c.mkdirAll(newDir) - dep := c.packageNamed("github.com/dvyukov/go-fuzz/go-fuzz-dep") - for _, f := range dep.GoFiles { - data := c.readFile(f) - // Eliminate the dot import. - data = bytes.Replace(data, []byte(`. "github.com/dvyukov/go-fuzz/go-fuzz-defs"`), nil, -1) - c.writeFile(filepath.Join(newDir, filepath.Base(f)), data) - } - - defs := c.packageNamed("github.com/dvyukov/go-fuzz/go-fuzz-defs") - for _, f := range defs.GoFiles { - data := c.readFile(f) - // Adjust package name to match go-fuzz-deps. - data = bytes.Replace(data, []byte("\npackage base"), []byte("\npackage gofuzzdep"), -1) - c.writeFile(filepath.Join(newDir, "defs.go"), data) - } -} - -func (c *Context) funcMain() []byte { - t := mainSrc - if *flagLibFuzzer { - t = mainSrcLibFuzzer - } - dot := map[string]interface{}{"Pkg": c.fuzzpkg.PkgPath, "AllFuncs": c.allFuncs, "DefaultFunc": *flagFunc} - buf := new(bytes.Buffer) - if err := t.Execute(buf, dot); err != nil { - c.failf("could not execute template: %v", err) - } - return buf.Bytes() -} - -func (c *Context) createFuzzMain() string { - mainPkg := filepath.Join(c.fuzzpkg.PkgPath, "go.fuzz.main") - path := filepath.Join(c.workdir, "gopath", "src", mainPkg) - c.mkdirAll(path) - c.writeFile(filepath.Join(path, "main.go"), c.funcMain()) - return mainPkg -} - -func (c *Context) clonePackage(p *packages.Package) { - root := "goroot" - if !c.std[p.PkgPath] { - root = "gopath" - } - newDir := filepath.Join(c.workdir, root, "src", p.PkgPath) - c.mkdirAll(newDir) - - // examine "go:embed" directives, collect embedded filenames, use later - for i, fullName := range p.CompiledGoFiles { - if strings.HasSuffix(fullName, ".go") { - for _, commentGroup := range trimComments(p.Syntax[i], p.Fset) { - for _, comment := range commentGroup.List { - if strings.HasPrefix(comment.Text, "//go:embed") { - filename := comment.Text[len("//go:embed "):] - dirname := filepath.Dir(fullName) - fullname := fmt.Sprintf("%s/%s", dirname, filename) - p.OtherFiles = append(p.OtherFiles, fullname) - } - } - } - } - } - - if p.PkgPath == "unsafe" { - // Write a dummy file. go/packages explicitly returns an empty GoFiles for it, - // for reasons that are unclear, but cmd/go wants there to be a Go file in the package. - c.writeFile(filepath.Join(newDir, "unsafe.go"), []byte(`package unsafe`)) - return - } - - // Copy all the source code. - - // Use GoFiles instead of CompiledGoFiles here. - // If we use CompiledGoFiles, we end up with code that cmd/go won't compile. - // See https://golang.org/issue/30479 and Context.instrumentPackages. - for _, f := range p.GoFiles { - dst := filepath.Join(newDir, filepath.Base(f)) - c.copyFile(f, dst) - } - for _, f := range p.OtherFiles { - dst := filepath.Join(newDir, filepath.Base(f)) - c.copyFile(f, dst) - } - - // TODO: do we need to look for and copy go.mod? -} - -// packageNamed extracts the package listed in path. -func (c *Context) packageNamed(path string) (pkgs *packages.Package) { - all := c.packagesNamed(path) - if len(all) != 1 { - c.failf("got multiple packages, requested only %v", path) - } - return all[0] -} - -// packagesNamed extracts the packages listed in paths. -func (c *Context) packagesNamed(paths ...string) (pkgs []*packages.Package) { - pre := func(p *packages.Package) bool { - for _, path := range paths { - if p.PkgPath == path { - pkgs = append(pkgs, p) - break - } - } - return len(pkgs) < len(paths) // continue only if we have not succeeded yet - } - packages.Visit(c.pkgs, pre, nil) - return pkgs -} - -func (c *Context) instrumentPackages(blocks *[]CoverBlock, sonar *[]CoverBlock) { - visit := func(pkg *packages.Package) { - if c.ignore[pkg.PkgPath] { - return - } - - root := "goroot" - if !c.std[pkg.PkgPath] { - root = "gopath" - } - path := filepath.Join(c.workdir, root, "src", pkg.PkgPath) // TODO: need filepath.FromSlash for pkg.PkgPath? - - for i, fullName := range pkg.CompiledGoFiles { - fname := filepath.Base(fullName) - if !strings.HasSuffix(fname, ".go") { - // This is a cgo-generated file. - // Instrumenting it currently does not work. - // We copied the original Go file as part of copyPackageRewrite, - // so we can just skip this one. - // See https://golang.org/issue/30479. - continue - } - f := pkg.Syntax[i] - - // TODO: rename trimComments? - f.Comments = trimComments(f, pkg.Fset) - - buf := new(bytes.Buffer) - content := c.readFile(fullName) - buf.Write(initialComments(content)) // Retain '// +build' directives. - instrument(pkg.PkgPath, fullName, pkg.Fset, f, pkg.TypesInfo, buf, blocks, sonar) - tmp := c.tempFile() - c.writeFile(tmp, buf.Bytes()) - outpath := filepath.Join(path, fname) - if runtime.GOOS == "windows" { - os.Remove(outpath) - } - c.moveFile(tmp, outpath) - } - } - - packages.Visit(c.pkgs, nil, visit) -} - -func (c *Context) copyDir(dir, newDir string) { - files, err := ioutil.ReadDir(dir) - if err != nil { - c.failf("failed to scan dir '%v': %v", dir, err) - } - c.mkdirAll(newDir) - for _, f := range files { - src := filepath.Join(dir, f.Name()) - dst := filepath.Join(newDir, f.Name()) - if f.IsDir() { - c.copyDir(src, dst) - } else { - c.copyFile(src, dst) - } - } -} - -func (c *Context) copyFile(src, dst string) { - r, err := os.Open(src) - if err != nil { - c.failf("copyFile: could not read %v", src, err) - } - w, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700) - if err != nil { - c.failf("copyFile: could not write %v: %v", dst, err) - } - if _, err := io.Copy(w, r); err != nil { - c.failf("copyFile: copying failed: %v", err) - } - if err := r.Close(); err != nil { - c.failf("copyFile: closing %v failed: %v", src, err) - } - if err := w.Close(); err != nil { - c.failf("copyFile: closing %v failed: %v", dst, err) - } -} - -func (c *Context) moveFile(src, dst string) { - c.copyFile(src, dst) - err := os.Remove(src) - if err != nil { - c.failf("moveFile: removing %q failed: %v", src, err) - } -} - -func (c *Context) failf(str string, args ...interface{}) { - c.cleanup() - fmt.Fprintf(os.Stderr, str+"\n", args...) - os.Exit(1) -} - -// tempFile creates and deletes a temp file, and returns its path. -// This is helpful when you need a temp path for an output file -// that will be created by an external tool (go build) or by a call to writeFile. -func (c *Context) tempFile() string { - outf, err := ioutil.TempFile("", "go-fuzz") - if err != nil { - c.failf("failed to create temp file: %v", err) - } - outf.Close() - os.Remove(outf.Name()) // necessary on Windows - return outf.Name() -} - -func (c *Context) readFile(name string) []byte { - data, err := ioutil.ReadFile(name) - if err != nil { - c.failf("failed to read temp file: %v", err) - } - return data -} - -func (c *Context) writeFile(name string, data []byte) { - if err := ioutil.WriteFile(name, data, 0700); err != nil { - c.failf("failed to write temp file: %v", err) - } -} - -func (c *Context) mkdirAll(dir string) { - if err := os.MkdirAll(dir, 0700); err != nil { - c.failf("failed to create temp dir: %v", err) - } -} - -var mainSrc = template.Must(template.New("main").Parse(` -package main - -import ( - target "{{.Pkg}}" - dep "go-fuzz-dep" -) - -func main() { - fns := []func([]byte)int { - {{range .AllFuncs}} - target.{{.}}, - {{end}} - } - dep.Main(fns) -} -`)) - -var mainSrcLibFuzzer = template.Must(template.New("main").Parse(` -package main - -import ( - "unsafe" - "reflect" - target "{{.Pkg}}" - dep "go-fuzz-dep" -) - -// #cgo CFLAGS: -Wall -Werror -// #ifdef __linux__ -// __attribute__((weak, section("__libfuzzer_extra_counters"))) -// #else -// #error Currently only Linux is supported -// #endif -// unsigned char GoFuzzCoverageCounters[65536]; -import "C" - -//export LLVMFuzzerInitialize -func LLVMFuzzerInitialize(argc uintptr, argv uintptr) int { - dep.Initialize(unsafe.Pointer(&C.GoFuzzCoverageCounters[0]), 65536) - return 0 -} - -//export LLVMFuzzerTestOneInput -func LLVMFuzzerTestOneInput(data uintptr, size uint64) int { - sh := &reflect.SliceHeader{ - Data: data, - Len: int(size), - Cap: int(size), - } - - input := *(*[]byte)(unsafe.Pointer(sh)) - target.{{.DefaultFunc}}(input) - - return 0 -} - -func main() { -} -`)) diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-defs/defs.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-defs/defs.go deleted file mode 100644 index b66d5abdf..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-defs/defs.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// Package defs provides constants required by go-fuzz-build, go-fuzz, and instrumented code. -package base - -// This package has a special interaction with go-fuzz-dep: -// It is copied into a package with it by go-fuzz-build. -// Only things that can be safely duplicated without confusion, -// like constants, should be added to this package. -// And any additions should be tested carefully. :) - -const ( - CoverSize = 64 << 10 - MaxInputSize = 1 << 20 - SonarRegionSize = 1 << 20 -) - -const ( - SonarEQL = iota - SonarNEQ - SonarLSS - SonarGTR - SonarLEQ - SonarGEQ - - SonarOpMask = 7 - SonarLength = 1 << 3 - SonarSigned = 1 << 4 - SonarString = 1 << 5 - SonarConst1 = 1 << 6 - SonarConst2 = 1 << 7 - - SonarHdrLen = 6 - SonarMaxLen = 20 -) diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/cover.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/cover.go deleted file mode 100644 index 46604ad5a..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/cover.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build gofuzz - -package gofuzzdep - -import ( - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -// Bool is just a bool. -// It is used by code autogenerated by go-fuzz-build -// to avoid compilation errors when a user's code shadows the built-in bool. -type Bool = bool - -// CoverTab holds code coverage. -// It is initialized to a new array so that instrumentation -// executed during process initialization has somewhere to write to. -// It is replaced by a newly initialized array when it is -// time for actual instrumentation to commence. -var CoverTab = new([CoverSize]byte) diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/doc.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/doc.go deleted file mode 100644 index c8adedb38..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Package gofuzzdep contains the business logic used to monitor the fuzzing. -// -// It is handled specially by go-fuzz-build; see the comments in package go-fuzz-defs. -// -// Be particularly careful about adding imports to go-fuzz-dep: -// Any package imported by go-fuzz-dep cannot be instrumented (on pain of import cycles), -// which reduces the effectiveness of go-fuzz on any other package that imports it. -// That is why (e.g.) there are hand-rolled serialization functions instead of using encoding/binary, -// and hand-rolled syscall-based communication instead of using package net or os. -package gofuzzdep diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main.go deleted file mode 100644 index 09bb3c581..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build gofuzz -// +build !gofuzz_libfuzzer - -package gofuzzdep - -import ( - "runtime" - "sync/atomic" - "syscall" - "time" - "unsafe" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -func Main(fns []func([]byte) int) { - mem, inFD, outFD := setupCommFile() - CoverTab = (*[CoverSize]byte)(unsafe.Pointer(&mem[0])) - input := mem[CoverSize : CoverSize+MaxInputSize] - sonarRegion = mem[CoverSize+MaxInputSize:] - runtime.GOMAXPROCS(1) // makes coverage more deterministic, we parallelize on higher level - for { - fnidx, n := read(inFD) - if n > uint64(len(input)) { - println("invalid input length") - syscall.Exit(1) - } - for i := range CoverTab { - CoverTab[i] = 0 - } - atomic.StoreUint32(&sonarPos, 0) - t0 := time.Now() - res := fns[fnidx](input[:n:n]) - ns := time.Since(t0) - write(outFD, uint64(res), uint64(ns), uint64(atomic.LoadUint32(&sonarPos))) - } -} - -// read reads little-endian-encoded uint8+uint64 from fd. -func read(fd FD) (uint8, uint64) { - rd := 0 - var buf [9]byte - for rd != len(buf) { - n, err := fd.read(buf[rd:]) - if err == syscall.EINTR { - continue - } - if n == 0 { - syscall.Exit(1) - } - if err != nil { - println("failed to read fd =", fd, "errno =", err.(syscall.Errno)) - syscall.Exit(1) - } - rd += n - } - return buf[0], deserialize64(buf[1:]) -} - -// write writes little-endian-encoded vals... to fd. -func write(fd FD, vals ...uint64) { - var tmp [3 * 8]byte - buf := tmp[:len(vals)*8] - for i, v := range vals { - serialize64(buf[i*8:], v) - } - wr := 0 - for wr != len(buf) { - n, err := fd.write(buf[wr:]) - if err == syscall.EINTR { - continue - } - if err != nil { - println("failed to read fd =", fd, "errno =", err.(syscall.Errno)) - syscall.Exit(1) - } - wr += n - } -} - -// writeStr writes strings s to fd. -func writeStr(fd FD, s string) { - buf := []byte(s) - wr := 0 - for wr != len(buf) { - n, err := fd.write(buf[wr:]) - if err == syscall.EINTR { - continue - } - if err != nil { - println("failed to read fd =", fd, "errno =", err.(syscall.Errno)) - syscall.Exit(1) - } - wr += n - } -} diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main_libFuzzer.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main_libFuzzer.go deleted file mode 100644 index 7a4911788..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/main_libFuzzer.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build gofuzz -// +build gofuzz_libfuzzer - -package gofuzzdep - -import ( - "unsafe" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -func Initialize(coverTabPtr unsafe.Pointer, coverTabSize uint64) { - if coverTabSize != CoverSize { - panic("Incorrect cover tab size") - } - CoverTab = (*[CoverSize]byte)(coverTabPtr) -} diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sonar.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sonar.go deleted file mode 100644 index e713c6d05..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sonar.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build gofuzz - -package gofuzzdep - -import ( - "sync/atomic" - "unsafe" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -var ( - sonarRegion []byte - sonarPos uint32 -) - -const failure = ^uint8(0) - -type iface struct { - typ unsafe.Pointer - val unsafe.Pointer -} - -// Sonar is called by instrumentation code to notify go-fuzz about comparisons. -// Low 8 bits of id are flags, the rest is unique id of a comparison. -func Sonar(v1, v2 interface{}, id uint32) { - var buf [SonarHdrLen + 2*SonarMaxLen]byte - n1, f1 := serialize(v1, v2, buf[SonarHdrLen:]) - if n1 == failure { - return - } - n2, f2 := serialize(v2, v1, buf[SonarHdrLen+n1:]) - if n2 == failure { - return - } - // Ideal const operands are converted to signed int, - // but it does not mean that the comparison is signed - // unless the other operand is signed. - if id&SonarConst1 != 0 { - f1 &^= SonarSigned - } - if id&SonarConst2 != 0 { - f2 &^= SonarSigned - } - id |= uint32(f1 | f2) - serialize32(buf[:], id) - buf[4] = n1 - buf[5] = n2 - n := uint32(SonarHdrLen + n1 + n2) - pos := atomic.LoadUint32(&sonarPos) - for { - if pos+n > uint32(len(sonarRegion)) { - return - } - if atomic.CompareAndSwapUint32(&sonarPos, pos, pos+n) { - break - } - pos = atomic.LoadUint32(&sonarPos) - } - copy(sonarRegion[pos:pos+n], buf[:]) -} - -func serialize(v, v2 interface{}, buf []byte) (n, flags uint8) { - switch vv := v.(type) { - case int8: - buf[0] = byte(vv) - return 1, SonarSigned - case uint8: - buf[0] = byte(vv) - return 1, 0 - case int16: - return serialize16(buf, uint16(vv)), SonarSigned - case uint16: - return serialize16(buf, vv), 0 - case int32: - return serialize32(buf, uint32(vv)), SonarSigned - case uint32: - return serialize32(buf, vv), 0 - case int64: - return serialize64(buf, uint64(vv)), SonarSigned - case uint64: - return serialize64(buf, vv), 0 - case int: - if unsafe.Sizeof(vv) == 4 { - return serialize32(buf, uint32(vv)), SonarSigned - } else { - return serialize64(buf, uint64(vv)), SonarSigned - } - case uint: - if unsafe.Sizeof(vv) == 4 { - return serialize32(buf, uint32(vv)), 0 - } else { - return serialize64(buf, uint64(vv)), 0 - } - case string: - if len(vv) > SonarMaxLen { - return failure, 0 - } - return uint8(copy(buf, vv)), SonarString - case [1]byte: - return uint8(copy(buf, vv[:])), SonarString - case [2]byte: - return uint8(copy(buf, vv[:])), SonarString - case [3]byte: - return uint8(copy(buf, vv[:])), SonarString - case [4]byte: - return uint8(copy(buf, vv[:])), SonarString - case [5]byte: - return uint8(copy(buf, vv[:])), SonarString - case [6]byte: - return uint8(copy(buf, vv[:])), SonarString - case [7]byte: - return uint8(copy(buf, vv[:])), SonarString - case [8]byte: - return uint8(copy(buf, vv[:])), SonarString - case [9]byte: - return uint8(copy(buf, vv[:])), SonarString - case [10]byte: - return uint8(copy(buf, vv[:])), SonarString - case [11]byte: - return uint8(copy(buf, vv[:])), SonarString - case [12]byte: - return uint8(copy(buf, vv[:])), SonarString - case [13]byte: - return uint8(copy(buf, vv[:])), SonarString - case [14]byte: - return uint8(copy(buf, vv[:])), SonarString - case [15]byte: - return uint8(copy(buf, vv[:])), SonarString - case [16]byte: - return uint8(copy(buf, vv[:])), SonarString - case [17]byte: - return uint8(copy(buf, vv[:])), SonarString - case [18]byte: - return uint8(copy(buf, vv[:])), SonarString - case [19]byte: - return uint8(copy(buf, vv[:])), SonarString - case [20]byte: - return uint8(copy(buf, vv[:])), SonarString - default: - // Special case: string literal is compared with a variable of - // user type with string underlying type: - // type Name string - // var name Name - // if name == "foo" { ... } - if _, ok := v2.(string); ok { - s := *(*string)((*iface)(unsafe.Pointer(&v)).val) - if len(s) <= SonarMaxLen { - return uint8(copy(buf[:], s)), SonarString - } - } - return failure, 0 - } -} - -// The serialization routines here match those of encoding/binary.LittleEndian. -// They are copied here because importing encoding/binary creates import cycles. - -func serialize16(buf []byte, v uint16) uint8 { - _ = buf[1] - buf[0] = byte(v >> 0) - buf[1] = byte(v >> 8) - return 2 -} - -func serialize32(buf []byte, v uint32) uint8 { - _ = buf[3] - buf[0] = byte(v >> 0) - buf[1] = byte(v >> 8) - buf[2] = byte(v >> 16) - buf[3] = byte(v >> 24) - return 4 -} - -func serialize64(buf []byte, v uint64) uint8 { - _ = buf[7] - buf[0] = byte(v >> 0) - buf[1] = byte(v >> 8) - buf[2] = byte(v >> 16) - buf[3] = byte(v >> 24) - buf[4] = byte(v >> 32) - buf[5] = byte(v >> 40) - buf[6] = byte(v >> 48) - buf[7] = byte(v >> 56) - return 8 -} - -func deserialize64(buf []byte) uint64 { - _ = buf[7] - return uint64(buf[0])<<0 | - uint64(buf[1])<<8 | - uint64(buf[2])<<16 | - uint64(buf[3])<<24 | - uint64(buf[4])<<32 | - uint64(buf[5])<<40 | - uint64(buf[6])<<48 | - uint64(buf[7])<<56 -} diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_posix.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_posix.go deleted file mode 100644 index 938cf9324..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_posix.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build darwin linux freebsd dragonfly openbsd netbsd -// +build gofuzz - -package gofuzzdep - -import ( - "syscall" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -type FD int - -func setupCommFile() ([]byte, FD, FD) { - mem, err := syscall.Mmap(3, 0, CoverSize+MaxInputSize+SonarRegionSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED) - if err != nil { - println("failed to mmap fd = 3 errno =", err.(syscall.Errno)) - syscall.Exit(1) - } - return mem, 4, 5 -} - -func (fd FD) read(buf []byte) (int, error) { - return syscall.Read(int(fd), buf) -} - -func (fd FD) write(buf []byte) (int, error) { - return syscall.Write(int(fd), buf) -} diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_windows.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_windows.go deleted file mode 100644 index 160301549..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-dep/sys_windows.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// +build gofuzz - -package gofuzzdep - -import ( - "syscall" - "unsafe" - - . "github.com/dvyukov/go-fuzz/go-fuzz-defs" -) - -// Can't import reflect because of import cycles. -type sliceHeader struct { - addr uintptr - l, c int -} - -type FD syscall.Handle - -func setupCommFile() ([]byte, FD, FD) { - const ( - size = CoverSize + MaxInputSize + SonarRegionSize - FILE_MAP_ALL_ACCESS = 0xF001F - ) - mapping := readEnvParam("GO_FUZZ_COMM_FD") - addr, err := syscall.MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, size) - if err != nil { - println("failed to mmap comm file:", err.Error()) - syscall.Exit(1) - } - hdr := sliceHeader{addr, size, size} - mem := *(*[]byte)(unsafe.Pointer(&hdr)) - in := FD(readEnvParam("GO_FUZZ_IN_FD")) - out := FD(readEnvParam("GO_FUZZ_OUT_FD")) - return mem, in, out -} - -func readEnvParam(name string) syscall.Handle { - v, _ := syscall.Getenv(name) - var x uintptr - for i := 0; i < len(v); i++ { - x = x*10 + uintptr(v[i]-'0') - } - return syscall.Handle(x) -} - -func (fd FD) read(buf []byte) (int, error) { - return syscall.Read(syscall.Handle(fd), buf) -} - -func (fd FD) write(buf []byte) (int, error) { - return syscall.Write(syscall.Handle(fd), buf) -} diff --git a/vendor/github.com/dvyukov/go-fuzz/internal/go-fuzz-types/types.go b/vendor/github.com/dvyukov/go-fuzz/internal/go-fuzz-types/types.go deleted file mode 100644 index 360481ff2..000000000 --- a/vendor/github.com/dvyukov/go-fuzz/internal/go-fuzz-types/types.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 go-fuzz project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// Package types provides types shared between go-fuzz-build and go-fuzz. -package types - -type CoverBlock struct { - ID int - File string - StartLine int - StartCol int - EndLine int - EndCol int - NumStmt int -} - -type Literal struct { - Val string - IsStr bool -} - -type MetaData struct { - Literals []Literal - Blocks []CoverBlock - Sonar []CoverBlock - Funcs []string // fuzz function names; must have length > 0 - DefaultFunc string // default function to fuzz -} |
