From 1fc6c8e049c73f51804ddb0c0df0ef2e1a7aec20 Mon Sep 17 00:00:00 2001 From: "alex.schade" <39062967+aschade92@users.noreply.github.com> Date: Thu, 10 Feb 2022 09:06:04 -0800 Subject: [PATCH] cmd/go/internal/modfetch: avoid leaking a lockedfile.File in case of write errors The go modules download command has a method called hashZip which checks the hash of a zipped directory versus an expected value, and then writes it out to a file. In the event that the write operation is not successful, we do not close the file, leading to it being leaked. This could happen if the user runs out of disk space, causing the underlying OS write command to return an error. Ultimately, this led to a panic in lockfile.OpenFile which was invoked from a finalizer garbage collecting the leaked file. The result was a stack trace that didn't show the call stack from where the write operation actually failed. Fixes #50858 --- src/cmd/go/internal/modfetch/fetch.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 0d1d875b81..cb8435ee1c 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -319,7 +319,7 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e // // If the hash does not match go.sum (or the sumdb if enabled), hashZip returns // an error and does not write ziphashfile. -func hashZip(mod module.Version, zipfile, ziphashfile string) error { +func hashZip(mod module.Version, zipfile, ziphashfile string) (err error) { hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash) if err != nil { return err @@ -331,8 +331,11 @@ func hashZip(mod module.Version, zipfile, ziphashfile string) error { if err != nil { return err } - // issue 50858: lockedfile.File leaked in case of write error - defer hf.Close() + defer func() { + if closeErr := hf.Close(); err != nil { + err = closeErr + } + }() if err := hf.Truncate(int64(len(hash))); err != nil { return err }