7
7
"strconv"
8
8
"sync"
9
9
10
+ "capnproto.org/go/capnp/v3/exp/bufferpool"
10
11
"capnproto.org/go/capnp/v3/flowcontrol"
11
12
"capnproto.org/go/capnp/v3/internal/syncutil"
12
13
)
@@ -114,9 +115,10 @@ type ClientKind = struct {
114
115
}
115
116
116
117
type client struct {
117
- creatorFunc int
118
- creatorFile string
119
- creatorLine int
118
+ creatorFunc int
119
+ creatorFile string
120
+ creatorStack string
121
+ creatorLine int
120
122
121
123
mu sync.Mutex // protects the struct
122
124
limiter flowcontrol.FlowLimiter
@@ -147,6 +149,19 @@ type clientHook struct {
147
149
resolvedHook * clientHook // valid only if resolved is closed
148
150
}
149
151
152
+ func (c Client ) setupLeakReporting (creatorFunc int ) {
153
+ if clientLeakFunc == nil {
154
+ return
155
+ }
156
+ c .creatorFunc = creatorFunc
157
+ _ , c .creatorFile , c .creatorLine , _ = runtime .Caller (2 )
158
+ buf := bufferpool .Default .Get (1e6 )
159
+ n := runtime .Stack (buf , false )
160
+ c .creatorStack = string (buf [:n ])
161
+ bufferpool .Default .Put (buf )
162
+ c .setFinalizer ()
163
+ }
164
+
150
165
// NewClient creates the first reference to a capability.
151
166
// If hook is nil, then NewClient returns nil.
152
167
//
@@ -165,11 +180,7 @@ func NewClient(hook ClientHook) Client {
165
180
}
166
181
h .resolvedHook = h
167
182
c := Client {client : & client {h : h }}
168
- if clientLeakFunc != nil {
169
- c .creatorFunc = 1
170
- _ , c .creatorFile , c .creatorLine , _ = runtime .Caller (1 )
171
- c .setFinalizer ()
172
- }
183
+ c .setupLeakReporting (1 )
173
184
return c
174
185
}
175
186
@@ -192,11 +203,7 @@ func NewPromisedClient(hook ClientHook) (Client, *ClientPromise) {
192
203
metadata : * NewMetadata (),
193
204
}
194
205
c := Client {client : & client {h : h }}
195
- if clientLeakFunc != nil {
196
- c .creatorFunc = 2
197
- _ , c .creatorFile , c .creatorLine , _ = runtime .Caller (1 )
198
- c .setFinalizer ()
199
- }
206
+ c .setupLeakReporting (2 )
200
207
return c , & ClientPromise {h : h }
201
208
}
202
209
@@ -460,11 +467,7 @@ func (c Client) AddRef() Client {
460
467
c .h .refs ++
461
468
c .h .mu .Unlock ()
462
469
d := Client {client : & client {h : c .h }}
463
- if clientLeakFunc != nil {
464
- d .creatorFunc = 3
465
- _ , d .creatorFile , d .creatorLine , _ = runtime .Caller (1 )
466
- d .setFinalizer ()
467
- }
470
+ d .setupLeakReporting (3 )
468
471
return d
469
472
}
470
473
@@ -653,6 +656,9 @@ func finalizeClient(c *client) {
653
656
} else {
654
657
msg = fmt .Sprintf ("leaked client created by %s on %s:%d" , fname , c .creatorFile , c .creatorLine )
655
658
}
659
+ if c .creatorStack != "" {
660
+ msg += "\n Creation stack trace:\n " + c .creatorStack + "\n "
661
+ }
656
662
657
663
// finalizeClient will only be called if clientLeakFunc != nil.
658
664
go clientLeakFunc (msg )
0 commit comments