呼び出し漏れリンターを
作ろうとした結果

Dennis Metzger
Go Night Talks - After Conference

Dennis(デニス) Metzger(メッツガー)

Backend Engineer @ Finatext

ソースコード

抽象構文木 (AST)

静的単一代入(SSA)形式

コールグラフ

ソースコード

  1. func Calc(a, b int) int {
  2. if a > b {
  3. a -= b
  4. }
  5. return a
  6. }

AST


*ast.FuncDecl
	Name: *ast.Ident "Calc"
	Body: *ast.BlockStmt
		0: *ast.IfStmt
			Cond: *ast.BinaryExpr
				X: *ast.Ident "a"
				Op: >
				Y: *ast.Ident "b"
			Body: *ast.BlockStmt
				0: *ast.AssignStmt
					Lhs: []ast.Expr
						0: *ast.Ident "a"
					Tok: -=
					Rhs: []ast.Expr
						0: *ast.Ident "b"
			Else: nil
							
    1: *ast.ReturnStmt Results: []ast.Expr 0: *ast.Ident "a"

SSA

  1. func Calc(a, b int) int {
  2. :0 {
  3. t0 := a > b
  4. if t0 goto 1 else 2
  5. }
  6. :1 {
  7. t1 := a - b
  8. jump 2
  9. }
  10. :2 {
  11. t2 := phi [0: a, 1: t1]
  12. return t2
  13. }
  14. }

抽象構文木 (AST) 静的単一代入(SSA)形式 コールグラフ

  1. fact := typesFact{pass.TypesInfo}
  2. pass.ExportPackageFact(&fact)
  3. prog := ssa.NewProgram(pass.Fset, ssa.InstantiateGenerics)
  4. seen := make(map[*types.Package]struct{})
  5. var addImports func(pp []*types.Package)
  6. addImports = func(pp []*types.Package) {
  7. for _, p := range pp {
  8. if _, ok := seen[p]; ok {
  9. continue
  10. }
  11. seen[p] = struct{}{}
  12. tfact := &typesFact{}
  13. if ok := pass.ImportPackageFact(p, tfact); !ok {
  14. pkg := prog.CreatePackage(p, nil, nil, true)
  15. pkg.Build()
  16. continue
  17. }
  18. files := slices.Collect(maps.Keys(tfact.typesInfo.FileVersions))
  19. pkg := prog.CreatePackage(p, files, tfact.typesInfo, true)
  20. addImports(p.Imports())
  21. pkg.Build()
  22. }
  23. }
  24. addImports(pass.Pkg.Imports())
  25. prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false)
  26. prog.Build()

func Create() {
	product.Tx(func() {
		autz.CanAccess()
	})
}

func Update() {
	product.Tx(func() {
		// なし
	})
}
						

package product

func Tx(f func()) {
	f()
}
						

関数が引数のケース:想定

関数が引数のケース:実際

想定通りだったとしても…

想定通りだったとしても…

想定通りだったとしても…

想定通りだったとしても…

想定通りだったとしても、検出漏れが発生する

全プログラムポインタ解析

ならできる?

精密なポインター解析は決定不能

フローに依存しない潜在的なエイリアスの
精密な解析もNP困難

結論、
リンターだと厳しいかも

厳しいけれども、次の一歩へ

  • 今回は、AST、SSA、コールグラフの知識という貴重な武器を手に入れた
  • これからは...
  • パターン検出にスコープを限定する
  • 他のリンター開発へ転用する

この課題を乗り越えるアイデアを、
ぜひ共有してください!