Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11720] ファイルの概要

このコミットは、Go言語のコマンドラインツールであるgo toolの呼び出しにおいて、標準入力(stdin)を使用できるようにする変更を導入しています。これにより、go toolが対話的な操作やパイプからの入力をより適切に処理できるようになり、特定のツール(例: go tool pprof)の使い勝手が向上しました。

コミット

commit 56ade2d8d5ca27a91ab829499cc0b0576f3297aa
Author: Russ Cox <rsc@golang.org>
Date:   Wed Feb 8 16:14:24 2012 -0500

    cmd/go: let go tool invocation use stdin
    
    Fixes #2921.
    
    R=golang-dev, n13m3y3r
    CC=golang-dev
    https://golang.org/cl/5647057

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/56ade2d8d5ca27a91ab829499cc0b0576f3297aa

元コミット内容

cmd/go: let go tool invocation use stdin
    
Fixes #2921.
    
R=golang-dev, n13m3y3r
CC=golang-dev
https://golang.org/cl/5647057

変更の背景

この変更は、Go言語のIssue #2921「'go tool pprof' does not start pprof in interactive mode」を修正するために行われました。go tool pprofのようなツールは、プロファイリングデータを分析する際に、ユーザーからの対話的な入力や、パイプを通じて渡されるデータを受け取る必要があります。しかし、当時のgo toolの内部実装では、実行されるサブプロセスに標準入力が適切に渡されていませんでした。このため、go tool pprofが対話モードで起動せず、ユーザーがプロファイリングデータを効率的に操作できないという問題が発生していました。

このコミットは、go toolが内部で他のコマンドを実行する際に、親プロセスの標準入力を子プロセスに引き継ぐようにすることで、この問題を解決しています。これにより、go toolを介して実行されるツールが、期待通りに標準入力からのデータを受け取れるようになり、対話的な利用やパイプライン処理が可能になりました。

前提知識の解説

go toolコマンド

go toolは、Go言語のツールチェインに含まれる低レベルなコマンドを実行するためのユーティリティです。go buildgo runのような高レベルなコマンドとは異なり、go toolはコンパイラ(compile)、アセンブラ(asm)、リンカ(link)、プロファイラ(pprof)など、Goのビルドシステムや開発環境を構成する個々のツールを直接呼び出すために使用されます。通常、開発者が直接go toolを使う機会は少ないですが、特定のデバッグや高度なビルド操作を行う際に利用されます。

標準入出力(stdin, stdout, stderr)

UNIXライクなシステムでは、すべてのプロセスはデフォルトで3つの標準ストリームを持っています。

  • 標準入力 (stdin): プロセスがデータを読み込むための入力ストリームです。通常、キーボードからの入力や、パイプ(|)で前のコマンドの出力が渡される場所です。
  • 標準出力 (stdout): プロセスが通常の出力データを書き込むための出力ストリームです。通常、ターミナルに表示されるか、リダイレクト(>)でファイルに書き込まれます。
  • 標準エラー出力 (stderr): プロセスがエラーメッセージや診断情報を書き込むための出力ストリームです。通常、標準出力とは別にターミナルに表示されるか、別のファイルにリダイレクトされます。

コマンドラインツールが対話的に動作したり、パイプラインの一部として機能したりするためには、これらの標準ストリームを適切に扱うことが不可欠です。

os/execパッケージ

Go言語の標準ライブラリであるos/execパッケージは、外部コマンドを実行するための機能を提供します。このパッケージを使用することで、Goプログラムからシェルコマンドや他の実行可能ファイルを起動し、その入出力を制御することができます。

os/execパッケージの主要な構造体はexec.Cmdです。この構造体は、実行するコマンドのパス、引数、環境変数、そして標準入出力ストリーム(Stdin, Stdout, Stderrフィールド)などを設定するために使用されます。

技術的詳細

このコミットの技術的な核心は、os/execパッケージのexec.Cmd構造体のStdinフィールドの利用にあります。

exec.Cmd構造体には、実行される子プロセスの標準入力を設定するためのStdinフィールドがあります。このフィールドはio.Readerインターフェースを満たす任意のオブジェクトを受け取ることができます。

  • Stdin: nil (デフォルト): 子プロセスは標準入力を持たず、入力しようとするとEOF(End Of File)を受け取ります。
  • Stdin: os.Stdin: 子プロセスの標準入力が、親プロセスの標準入力(つまり、goコマンド自体が受け取っている標準入力)に接続されます。これにより、親プロセスに渡された入力がそのまま子プロセスに流れるようになります。

この変更以前は、go toolが内部で呼び出すコマンドのStdinフィールドは明示的に設定されていなかったため、デフォルトのnil状態でした。そのため、子プロセスは標準入力からの入力を受け取ることができず、対話的な動作が不可能でした。

このコミットでは、toolCmd.Stdin = os.Stdinという一行を追加することで、この問題を解決しています。これにより、go toolが実行するサブコマンドは、goコマンドが受け取った標準入力をそのまま利用できるようになり、対話的な操作やパイプからのデータ処理が可能になりました。

コアとなるコードの変更箇所

--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -70,6 +70,7 @@ func runTool(cmd *Command, args []string) {
 	toolCmd := &exec.Cmd{
 		Path:   toolPath,
 		Args:   args,
+		Stdin:  os.Stdin,
 		Stdout: os.Stdout,
 		Stderr: os.Stderr,
 	}

コアとなるコードの解説

変更はsrc/cmd/go/tool.goファイルのrunTool関数内で行われています。この関数は、go toolコマンドが内部で他のツールを実行する際に呼び出されます。

変更前のコードでは、exec.Cmd構造体の初期化時にStdinフィールドが明示的に設定されていませんでした。Goでは、構造体のフィールドが初期化時に明示的に値が与えられない場合、その型のゼロ値で初期化されます。io.Readerインターフェースのゼロ値はnilであるため、Stdinnilとなっていました。

追加された一行 Stdin: os.Stdin, は、toolCmdというexec.Cmd構造体のStdinフィールドに、os.Stdinという値を代入しています。

  • os.Stdinは、Goプログラムが起動された際に自動的に開かれる標準入力ファイルディスクリプタを表す*os.File型(io.Readerインターフェースを満たす)のグローバル変数です。

この変更により、go toolによって起動される子プロセス(例: pprof)は、親プロセスであるgoコマンドの標準入力を共有するようになります。結果として、ユーザーがgo tool pprofを実行し、キーボードから入力したり、他のコマンドの出力をパイプで渡したりした場合、その入力がpprofツールに正しく渡されるようになります。これにより、pprofのような対話的なツールが期待通りに動作するようになり、Issue #2921が解決されました。

関連リンク

参考にした情報源リンク

  • GitHub Issue #2921 in the golang/go repository: This issue, titled "'go tool pprof' does not start pprof in interactive mode," was opened in 2012 and has since been fixed and marked as "FrozenDueToAge."
  • Go Packages Vulnerability Report GO-2024-2921: This is a recent vulnerability report (published July 1, 2024) concerning github.com/hashicorp/vault. It describes how HashiCorp Vault incorrectly validated JSON Web Tokens (JWT) Audience Claims, identified as CVE-2024-5798 and GHSA-32cj-5wx4-gq8p.
  • EulerOS-SA-2024-2921 (Vulnerability Database Entry): This refers to a vulnerability in golang on EulerOS 2.0 SP12 (CVE-2024-24791). It describes how the net/http HTTP/1.1 client mishandled responses to 'Expect: 100-continue' headers, which could lead to a denial of service.