77 lines
1.5 KiB
Go
77 lines
1.5 KiB
Go
package helpers
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"go/ast"
|
||
|
|
"go/parser"
|
||
|
|
"go/token"
|
||
|
|
"io/fs"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Go never frees syscall.NewCallback (hard cap ~2000). Creating one per
|
||
|
|
// screenshot frame is a fatal "too many callback functions".
|
||
|
|
func TestNewCallbackOnlyAtPackageScope(t *testing.T) {
|
||
|
|
root := filepath.Join("..", "..")
|
||
|
|
fset := token.NewFileSet()
|
||
|
|
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if d.IsDir() {
|
||
|
|
name := d.Name()
|
||
|
|
if name == ".git" || name == "vendor" || name == "testdata" {
|
||
|
|
return filepath.SkipDir
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if !strings.HasSuffix(path, ".go") {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
file, err := parser.ParseFile(fset, path, nil, 0)
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("parse %s: %v", path, err)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
for _, decl := range file.Decls {
|
||
|
|
fn, ok := decl.(*ast.FuncDecl)
|
||
|
|
if !ok {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
ast.Inspect(fn, func(n ast.Node) bool {
|
||
|
|
if !isNewCallbackCall(n) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
name := fn.Name.Name
|
||
|
|
if fn.Recv != nil {
|
||
|
|
name = "method " + name
|
||
|
|
}
|
||
|
|
t.Errorf("%s: syscall.NewCallback inside %s; Go never frees these (cap ~2000)", fset.Position(n.Pos()), name)
|
||
|
|
return true
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func isNewCallbackCall(n ast.Node) bool {
|
||
|
|
call, ok := n.(*ast.CallExpr)
|
||
|
|
if !ok {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||
|
|
if !ok {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
switch sel.Sel.Name {
|
||
|
|
case "NewCallback", "NewCallbackCDecl":
|
||
|
|
return true
|
||
|
|
default:
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|