Repository: go
Issue: x/perf: resource leaks from unclosed objects reported by staticmajor
Labels: NeedsFix,compiler/runtime

### What did you do?
Ran [staticmajor](https://github.com/marketplace/actions/staticmajor-analyzer) within Orijtech Inc, and it produced this manifest of issues
```shell
/go/src/golang.org/x/perf/storage/client.go:228:3: leaking resource created on line 224
/go/src/golang.org/x/perf/storage/db/db.go:57:3: leaking resource created on line 55
/go/src/golang.org/x/perf/storage/db/db.go:60:3: leaking resource created on line 55
/go/src/golang.org/x/perf/storage/db/db.go:250:18: leaking resource
/go/src/golang.org/x/perf/storage/db/db.go:232:15: leaking resource
/go/src/golang.org/x/perf/storage/fs/gcs/gcs.go:22:34: leaking resource
```

in which:
* there are sql.Statements that are unclosed because they were created like this `_, err = tx.Stmt(db.insertUpload).Exec(id, day, num)`
* there is an unclosed sql.DB in case of an error
* a multipart.Writer is unnecessarily created before an HTTP request is constructed and doesn't error
* the `storage/fs.FS` abstraction makes it so that `storage/fs/gcs.NewWriter` creates a Google Cloud Storage client that never gets closed

the resource leaks are real and all resource leaks except for the storage.Client resource leak can be fixed by this diff
```diff
diff --git a/storage/client.go b/storage/client.go
index 12d6ce2..dee1e49 100644
--- a/storage/client.go
+++ b/storage/client.go
@@ -221,12 +221,13 @@ func (c *Client) NewUpload(ctx context.Context) *Upload {
 	hc := c.httpClient()
 
 	pr, pw := io.Pipe()
-	mpw := multipart.NewWriter(pw)
 
 	req, err := http.NewRequest("POST", c.BaseURL+"/upload", pr)
 	if err != nil {
 		return &Upload{err: err}
 	}
+
+	mpw := multipart.NewWriter(pw)
 	req.Header.Set("Content-Type", mpw.FormDataContentType())
 	req.Header.Set("User-Agent", "golang.org/x/perf/storage")
 	errCh := make(chan error)
diff --git a/storage/db/db.go b/storage/db/db.go
index 1d92d24..8ed33d2 100644
--- a/storage/db/db.go
+++ b/storage/db/db.go
@@ -42,11 +42,17 @@ type DB struct {
 // the same as the parameters for sql.Open. Only mysql and sqlite3 are
 // explicitly supported; other database engines will receive MySQL
 // query syntax which may or may not be compatible.
-func OpenSQL(driverName, dataSourceName string) (*DB, error) {
+func OpenSQL(driverName, dataSourceName string) (_ *DB, rerr error) {
 	db, err := sql.Open(driverName, dataSourceName)
 	if err != nil {
 		return nil, err
 	}
+	defer func() {
+		if rerr != nil {
+			db.Close()
+		}
+	}()
+
 	if hook := openHooks[driverName]; hook != nil {
 		if err := hook(db); err != nil {
 			return nil, err
@@ -229,7 +235,10 @@ func (db *DB) NewUpload(ctx context.Context) (*Upload, error) {
 		}
 	}()
 	var lastID string
-	err = tx.Stmt(db.lastUpload).QueryRow().Scan(&lastID)
+	stmt := tx.Stmt(db.lastUpload)
+	err = stmt.QueryRow().Scan(&lastID)
+	stmt.Close()
+
 	switch err {
 	case sql.ErrNoRows:
 	case nil:
@@ -247,7 +256,9 @@ func (db *DB) NewUpload(ctx context.Context) (*Upload, error) {
 
 	id := fmt.Sprintf("%s.%d", day, num)
 
-	_, err = tx.Stmt(db.insertUpload).Exec(id, day, num)
+	stmt = tx.Stmt(db.insertUpload)
+	_, err = stmt.Exec(id, day, num)
+	stmt.Close()
 	if err != nil {
 		return nil, err
 	}
```

Kind FYI for @kirbyquerby @elias-orijtech @willpoint @jhusdero