Skip to content

Commit a05aa2a

Browse files
committed
internal/symbols: compute patched symbols for a given commit
This is part of a series of CLs implementing automatic symbol extraction. Change-Id: I3aa0485a597005622d4be40ac2aea5fe5b55467f Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/536297 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Zvonimir Pavlinovic <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Tatiana Bradley <[email protected]>
1 parent 25fbceb commit a05aa2a

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

internal/gitrepo/gitrepo.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"golang.org/x/vulndb/internal/worker/log"
2424
)
2525

26-
// Clone returns a repo by cloning the repo at repoURL.
26+
// Clone returns a bare repo by cloning the repo at repoURL.
2727
func Clone(ctx context.Context, repoURL string) (repo *git.Repository, err error) {
2828
defer derrors.Wrap(&err, "gitrepo.Clone(%q)", repoURL)
2929
ctx = event.Start(ctx, "gitrepo.Clone")
@@ -39,6 +39,22 @@ func Clone(ctx context.Context, repoURL string) (repo *git.Repository, err error
3939
})
4040
}
4141

42+
// PlainClone returns a (non-bare) repo with its history by cloning the repo at repoURL.
43+
func PlainClone(ctx context.Context, dir, repoURL string) (repo *git.Repository, err error) {
44+
defer derrors.Wrap(&err, "gitrepo.PlainClone(%q)", repoURL)
45+
ctx = event.Start(ctx, "gitrepo.PlainClone")
46+
defer event.End(ctx)
47+
48+
log.Infof(ctx, "Plain cloning repo %q at HEAD", repoURL)
49+
return git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
50+
URL: repoURL,
51+
ReferenceName: plumbing.HEAD,
52+
SingleBranch: true, // allow branches other than master
53+
Depth: 0, // pull in history
54+
Tags: git.NoTags,
55+
})
56+
}
57+
4258
// Open returns a repo by opening the repo at the local path dirpath.
4359
func Open(ctx context.Context, dirpath string) (repo *git.Repository, err error) {
4460
defer derrors.Wrap(&err, "gitrepo.Open(%q)", dirpath)

internal/symbols/patched_functions.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package symbols
66

77
import (
88
"bytes"
9+
"context"
910
"errors"
1011
"fmt"
1112
"go/ast"
@@ -19,9 +20,84 @@ import (
1920
"reflect"
2021
"strings"
2122

23+
"github.com/go-git/go-git/v5"
24+
"github.com/go-git/go-git/v5/plumbing"
2225
"golang.org/x/mod/modfile"
26+
"golang.org/x/vulndb/internal/derrors"
27+
"golang.org/x/vulndb/internal/gitrepo"
2328
)
2429

30+
// Patched returns symbols of module patched in commit identified
31+
// by commitHash. repoURL is URL of the git repository containing
32+
// the module.
33+
//
34+
// Patched returns a map from package import paths to symbols
35+
// patched in the package. Test packages and symbols are omitted.
36+
//
37+
// If the commit has more than one parent, an error is returned.
38+
func Patched(module, repoURL, commitHash string) (_ map[string][]string, err error) {
39+
defer derrors.Wrap(&err, "Patched(%s ,%s, %s)", module, repoURL, commitHash)
40+
41+
repoRoot, err := os.MkdirTemp("", commitHash)
42+
if err != nil {
43+
return nil, err
44+
}
45+
defer func() {
46+
_ = os.RemoveAll(repoRoot)
47+
}()
48+
49+
ctx := context.Background()
50+
repo, err := gitrepo.PlainClone(ctx, repoRoot, repoURL)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
w, err := repo.Worktree()
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
hash := plumbing.NewHash(commitHash)
61+
commit, err := repo.CommitObject(hash)
62+
if err != nil {
63+
return nil, err
64+
}
65+
66+
if commit.NumParents() != 1 {
67+
return nil, fmt.Errorf("more than 1 parent: %d", commit.NumParents())
68+
}
69+
70+
parent, err := commit.Parent(0)
71+
if err != nil {
72+
return nil, err
73+
}
74+
75+
if err := w.Checkout(&git.CheckoutOptions{Hash: hash, Force: true}); err != nil {
76+
return nil, err
77+
}
78+
79+
newSymbols, err := moduleSymbols(repoRoot, module)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
if err := w.Checkout(&git.CheckoutOptions{Hash: parent.Hash, Force: true}); err != nil {
85+
return nil, err
86+
}
87+
88+
oldSymbols, err := moduleSymbols(repoRoot, module)
89+
if err != nil {
90+
return nil, err
91+
}
92+
93+
patched := patchedSymbols(oldSymbols, newSymbols)
94+
pkgSyms := make(map[string][]string)
95+
for _, sym := range patched {
96+
pkgSyms[sym.pkg] = append(pkgSyms[sym.pkg], sym.symbol)
97+
}
98+
return pkgSyms, nil
99+
}
100+
25101
// patchedSymbols returns symbol indices in oldSymbols that either 1) cannot
26102
// be identified in newSymbols or 2) the corresponding functions have their
27103
// source code changed.

0 commit comments

Comments
 (0)