Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EAR pointer analysis: add inter-procedural support #308

Merged
merged 8 commits into from
May 5, 2021
Merged
21 changes: 15 additions & 6 deletions internal/pkg/earpointer/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ import (
"strconv"
"strings"

"golang.org/x/tools/go/types/typeutil"

"github.com/google/go-flow-levee/internal/pkg/config"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil"
)

// Analyzer traverses the packages and constructs an EAR partitions
Expand Down Expand Up @@ -434,17 +433,27 @@ func (vis *visitor) visitBuiltin(builtin *ssa.Builtin, instr ssa.Instruction) {
// Collect unification constraints corresponding to a call.
// This generates constraints for unifying parameters, free variables, and return values.
func (vis *visitor) collectCalleeConstraints(common *ssa.CallCommon, fn *ssa.Function, instr ssa.Instruction) (map[ssa.Value][]ssa.Value, map[ssa.Value][][]ssa.Value) {
// Handle undefined/unknown functions.
if fn == nil || len(fn.Blocks) == 0 || len(fn.Params) != len(common.Args) {
// Handle undefined/unlinked functions.
if fn == nil || len(fn.Blocks) == 0 {
return nil, nil
}
// TODO: in some rare cases, SSA may generate an imported function with no arguments while this function actually
// takes arguments. Skip such functions here.
if len(fn.Params) != len(common.Args) {
return nil, nil
}

paramCstrs := make(map[ssa.Value][]ssa.Value)
// Add caller_reg -> {callee_reg} constraints for parameters.
// For example, for g(a, b) and func g(x, y), add <a, g.x> and
// <b, g.y> into the constraints.
// Disable the unification of receivers here to avoid too many FPs.
// This may lead to under-approximation and FNs of the checkers.
//
// Unifying the receivers may cause too many FPs.
// For example, func (t T) f() { ... }; o1.f() and o2.f(), the unification
// results in {o1, o2, t}, while o1 and o2 should not be unified.
// So the receiver unification is disabled here, which may lead to under-approximation
// and FNs of the checkers.
// TODO: support context-sensitivity to mitigate this issue.
start := 0
if fn.Signature.Recv() != nil {
start = 1
Expand Down
5 changes: 3 additions & 2 deletions internal/pkg/earpointer/analysis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,8 +891,9 @@ func TestVariadicCall(t *testing.T) {
if err != nil {
t.Fatal(err)
}
want := "{f.a,f.t4,g.t1}: [], {f.b}: [], {f.t0,f.t3,g.ks}: " +
"[0->g.t0, 1->f.t2], {f.t1,g.t0}: --> g.t1, {f.t2}: --> f.b"
want := "{f.a,f.t4,g.t1}: [], {f.b}: [], " +
guodongli-google marked this conversation as resolved.
Show resolved Hide resolved
"{f.t0,f.t3,g.ks}: [0->g.t0, 1->f.t2], " +
"{f.t1,g.t0}: --> g.t1, {f.t2}: --> f.b"
if got := state.String(); got != want {
t.Errorf("got: %s\n want: %s", got, want)
}
Expand Down