aboutsummaryrefslogtreecommitdiff
path: root/src/fmt
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2018-09-18 12:52:39 -0700
committerJoe Tsai <thebrokentoaster@gmail.com>2018-09-19 18:01:04 +0000
commite82d152e66e81812a5c6ebf075cc99efd2602b19 (patch)
treeebcc63f40fa75e8fe4e118a2e4ae1150c4665366 /src/fmt
parent620bd5a3bc640f60a00d8b49c27c51e8ce67e67b (diff)
downloadgo-e82d152e66e81812a5c6ebf075cc99efd2602b19.tar.gz
go-e82d152e66e81812a5c6ebf075cc99efd2602b19.zip
fmt: fix usage of sync.Pool
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>
Diffstat (limited to 'src/fmt')
-rw-r--r--src/fmt/print.go10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/fmt/print.go b/src/fmt/print.go
index c9d694b07d..32743d0712 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -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{}