Skip to content
This repository was archived by the owner on Jun 2, 2023. It is now read-only.

Commit 2847da2

Browse files
authored
Merge pull request timakin#3 from timakin/feature/recursive-search-for-indirect-func
Feature/recursive search for indirect func
2 parents 392eb43 + 8da3681 commit 2847da2

File tree

3 files changed

+100
-18
lines changed

3 files changed

+100
-18
lines changed

main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,3 @@ import (
88
)
99

1010
func main() { singlechecker.Main(bodyclose.Analyzer) }
11-

passes/bodyclose/bodyclose.go

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,32 +109,62 @@ func (r *runner) isopen(b *ssa.BasicBlock, i int) bool {
109109
if !ok {
110110
continue
111111
}
112+
112113
if len(*val.Referrers()) == 0 {
113114
return true
114115
}
115116
resRefs := *val.Referrers()
116117
for _, resRef := range resRefs {
117-
b, ok := resRef.(*ssa.FieldAddr)
118-
if !ok {
119-
continue
120-
}
121-
if b.Referrers() == nil {
122-
return true
123-
}
118+
switch resRef := resRef.(type) {
119+
case *ssa.Store: // Call in Closure function
120+
if len(*resRef.Addr.Referrers()) == 0 {
121+
return true
122+
}
123+
124+
for _, aref := range *resRef.Addr.Referrers() {
125+
if c, ok := aref.(*ssa.MakeClosure); ok {
126+
f := c.Fn.(*ssa.Function)
127+
if r.noImportedNetHTTP(f) {
128+
// skip this
129+
continue
130+
}
131+
called := r.isClosureCalled(c)
132+
133+
for _, b := range f.Blocks {
134+
for i := range b.Instrs {
135+
return r.isopen(b, i) || !called
136+
}
137+
}
138+
}
124139

125-
bRefs := *b.Referrers()
126-
for _, bRef := range bRefs {
127-
bOp, ok := r.getBodyOp(bRef)
128-
if !ok {
129-
continue
130140
}
131-
if len(*bOp.Referrers()) == 0 {
141+
case *ssa.Call: // Indirect function call
142+
if f, ok := resRef.Call.Value.(*ssa.Function); ok {
143+
for _, b := range f.Blocks {
144+
for i := range b.Instrs {
145+
return r.isopen(b, i)
146+
}
147+
}
148+
}
149+
case *ssa.FieldAddr: // Normal reference to response entity
150+
if resRef.Referrers() == nil {
132151
return true
133152
}
134-
ccalls := *bOp.Referrers()
135-
for _, ccall := range ccalls {
136-
if r.isCloseCall(ccall) {
137-
return false
153+
154+
bRefs := *resRef.Referrers()
155+
for _, bRef := range bRefs {
156+
bOp, ok := r.getBodyOp(bRef)
157+
if !ok {
158+
continue
159+
}
160+
if len(*bOp.Referrers()) == 0 {
161+
return true
162+
}
163+
ccalls := *bOp.Referrers()
164+
for _, ccall := range ccalls {
165+
if r.isCloseCall(ccall) {
166+
return false
167+
}
138168
}
139169
}
140170
}
@@ -191,6 +221,20 @@ func (r *runner) isCloseCall(ccall ssa.Instruction) bool {
191221
return false
192222
}
193223

224+
func (r *runner) isClosureCalled(c *ssa.MakeClosure) bool {
225+
refs := *c.Referrers()
226+
if len(refs) == 0 {
227+
return false
228+
}
229+
for _, ref := range refs {
230+
if _, ok := ref.(*ssa.Call); ok {
231+
return true
232+
}
233+
}
234+
235+
return false
236+
}
237+
194238
func (r *runner) noImportedNetHTTP(f *ssa.Function) (ret bool) {
195239
obj := f.Object()
196240
if obj == nil {

passes/bodyclose/testdata/src/a/a.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,42 @@ func f5() {
7474
func f6() {
7575
http.Get("http://example.com/") // want "response body must be closed"
7676
}
77+
78+
func f7() {
79+
res, _ := http.Get("http://example.com/") // OK
80+
resCloser := func() {
81+
res.Body.Close()
82+
}
83+
resCloser()
84+
}
85+
86+
func f8() {
87+
res, _ := http.Get("http://example.com/") // want "response body must be closed"
88+
_ = func() {
89+
res.Body.Close()
90+
}
91+
}
92+
93+
func f9() {
94+
_ = func() {
95+
res, _ := http.Get("http://example.com/") // OK
96+
res.Body.Close()
97+
}
98+
}
99+
100+
func f10() {
101+
res, _ := http.Get("http://example.com/") // OK
102+
resCloser := func(res *http.Response) {
103+
res.Body.Close()
104+
}
105+
resCloser(res)
106+
}
107+
108+
func handleResponse(res *http.Response) {
109+
res.Body.Close()
110+
}
111+
112+
func f11() {
113+
res, _ := http.Get("http://example.com/") // OK
114+
handleResponse(res)
115+
}

0 commit comments

Comments
 (0)