]> Cypherpunks.ru repositories - gostls13.git/commitdiff
fmt: fix usage of sync.Pool
authorJoe Tsai <joetsai@digital-static.net>
Tue, 18 Sep 2018 19:52:39 +0000 (12:52 -0700)
committerJoe Tsai <thebrokentoaster@gmail.com>
Wed, 19 Sep 2018 18:01:04 +0000 (18:01 +0000)
The current usage of sync.Pool is leaky because it stores an arbitrary
sized buffer into the pool. However, sync.Pool assumes that all items in the
pool are interchangeable from a memory cost perspective. Due to the unbounded
size of a buffer that may be added, it is possible for the pool to eventually
pin arbitrarily large amounts of memory in a live-lock situation.

As a simple fix, we just set a maximum size that we permit back into the pool.

We do not need to fix the use of a sync.Pool in scan.go since the free method
has always enforced a maximum capacity since the first commit of the scan logic.

Fixes #27740
Updates #23199

Change-Id: I875278f7dba42625405df36df3e9b028252ce5e3
Reviewed-on: https://go-review.googlesource.com/136116
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/fmt/print.go

index c9d694b07dc88dcf62b492cb7f0a2819ad9bc4c3..32743d07123c17665e6b390bdcb898cb30ce97d9 100644 (file)
@@ -139,6 +139,16 @@ func newPrinter() *pp {
 
 // free saves used pp structs in ppFree; avoids an allocation per invocation.
 func (p *pp) free() {
+       // Proper usage of a sync.Pool requires each entry to have approximately
+       // the same memory cost. To obtain this property when the stored type
+       // contains a variably-sized buffer, we add a hard limit on the maximum buffer
+       // to place back in the pool.
+       //
+       // See https://golang.org/issue/23199
+       if cap(p.buf) > 64<<10 {
+               return
+       }
+
        p.buf = p.buf[:0]
        p.arg = nil
        p.value = reflect.Value{}