From 4482f62a26b5f66c1223b469b245ef8d65bae81a Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Mon, 14 Feb 2022 17:03:56 +0000
Subject: [PATCH] Prevent dangling GetAttribute calls (#18754)

It appears possible that there could be a hang due to unread data from the
repo-attribute command pipes. This PR simply closes these during the defer.

Signed-off-by: Andrew Thornton <art27@cantab.net>
---
 modules/git/repo_attribute.go              | 14 ++++++++------
 modules/git/repo_language_stats_nogogit.go |  5 ++++-
 services/gitdiff/gitdiff.go                |  1 +
 3 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go
index d31203aabd..772ee6ad12 100644
--- a/modules/git/repo_attribute.go
+++ b/modules/git/repo_attribute.go
@@ -185,7 +185,8 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
 // Run run cmd
 func (c *CheckAttributeReader) Run() error {
 	defer func() {
-		_ = c.Close()
+		_ = c.stdinReader.Close()
+		_ = c.stdOut.Close()
 	}()
 	stdErr := new(bytes.Buffer)
 	err := c.cmd.RunWithContext(&RunContext{
@@ -196,14 +197,17 @@ func (c *CheckAttributeReader) Run() error {
 		Stdout:  c.stdOut,
 		Stderr:  stdErr,
 		PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
-			close(c.running)
+			select {
+			case <-c.running:
+			default:
+				close(c.running)
+			}
 			return nil
 		},
 	})
 	if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" {
 		return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
 	}
-
 	return nil
 }
 
@@ -243,10 +247,8 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
 
 // Close close pip after use
 func (c *CheckAttributeReader) Close() error {
-	err := c.stdinWriter.Close()
-	_ = c.stdinReader.Close()
-	_ = c.stdOut.Close()
 	c.cancel()
+	err := c.stdinWriter.Close()
 	select {
 	case <-c.running:
 	default:
diff --git a/modules/git/repo_language_stats_nogogit.go b/modules/git/repo_language_stats_nogogit.go
index 0b21bf6344..adb11dd8fa 100644
--- a/modules/git/repo_language_stats_nogogit.go
+++ b/modules/git/repo_language_stats_nogogit.go
@@ -88,7 +88,10 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
 					}
 				}()
 			}
-			defer cancel()
+			defer func() {
+				_ = checker.Close()
+				cancel()
+			}()
 		}
 	}
 
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 017341d63f..58c25ff98f 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -1422,6 +1422,7 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
 				}()
 			}
 			defer func() {
+				_ = checker.Close()
 				cancel()
 			}()
 		}