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

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

このコミットは、Go言語の標準ライブラリである sort パッケージ内のテストファイル src/pkg/sort/sort_test.go における32ビットビルド時の問題を修正するものです。具体的には、テストで使用される maxswap の値が32ビット環境でオーバーフローを引き起こす可能性があったため、その値を修正しています。

コミット

commit 6d2d4ba94fb94dd5a9f581a1606d720bed8131dd
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jul 1 21:44:14 2013 -0400

    sort: fix 32-bit build
    
    TBR=golang-dev
    CC=golang-dev
    https://golang.org/cl/10856043

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

https://github.com/golang/go/commit/6d2d4ba94fb94dd5a9f581a1606d720bed8131dd

元コミット内容

sort: fix 32-bit build

TBR=golang-dev
CC=golang-dev
https://golang.org/cl/10856043

変更の背景

このコミットの背景には、Go言語の sort パッケージのテストコードが、32ビットアーキテクチャのシステムでビルドまたは実行された際に問題を引き起こす可能性があったという事実があります。具体的には、sort_test.go 内で定義されている maxswap という変数の初期値が、32ビット符号付き整数の最大値を超える可能性のある表現 1 << 31 を使用していました。

32ビットシステムでは、符号付き整数(int型など)の最大値は 2^31 - 1 (約21億) です。1 << 31 はビットシフト演算で 2^31 を意味します。これは、32ビット符号付き整数の表現可能な範囲のちょうど外側、つまり最上位ビットがセットされた状態になります。多くのプログラミング言語やシステムにおいて、この値は負の数として解釈されるか、あるいはオーバーフローエラーを引き起こす可能性があります。

Go言語の int 型は、実行環境のアーキテクチャに依存して32ビットまたは64ビットのいずれかになります。このため、64ビットシステムでは問題なく動作していたコードが、32ビットシステムでは予期せぬ挙動を示すことがありました。このコミットは、このようなクロスプラットフォーム互換性の問題を解消し、sort パッケージのテストがすべてのサポートされるアーキテクチャで正しく動作するようにするためのものです。

前提知識の解説

1. ビットシフト演算子 (<<)

A << B は、数値 A のビットを B ビットだけ左にシフトする演算です。左シフトは、数値を 2^B 倍することに相当します。 例: 1 << 01 (2^0) 1 << 12 (2^1) 1 << 24 (2^2) 1 << 312^31 を意味します。

2. 符号付き整数とビット表現

コンピュータでは、整数は通常、固定されたビット数で表現されます。例えば、32ビット整数は32個のバイナリビットで構成されます。符号付き整数では、最上位ビット(一番左のビット)が数値の符号を表すために使用されます(0は正、1は負)。これにより、32ビット符号付き整数で表現できる値の範囲は、約 -2^31 から 2^31 - 1 までとなります。

  • 32ビット符号付き整数の最大値: 2^31 - 1 (バイナリで 0111...111、1が31個続く)
  • 2^31 の表現: バイナリで 1000...000 (1の後に0が31個続く)。この値は、32ビット符号付き整数として解釈されると、通常は最小の負の数(-2^31)として扱われます。

3. Go言語の int

Go言語の int 型は、プラットフォームに依存する整数型です。

  • 32ビットシステム(例: GOARCH=386)では、int は32ビット幅です。
  • 64ビットシステム(例: GOARCH=amd64)では、int は64ビット幅です。

この特性により、1 << 31 のような定数式は、32ビットシステムではオーバーフローを引き起こす可能性がありますが、64ビットシステムでは問題なく 2^31 として扱われます。

4. sort パッケージ

Go言語の sort パッケージは、スライス(Goのスライスは動的配列のようなもの)をソートするための汎用的なインターフェースとアルゴリズムを提供します。sort.Interface インターフェースを実装することで、任意のデータ型をソートできます。このコミットで変更された sort_test.go は、このパッケージのソートアルゴリズムのテストを行うためのものです。

技術的詳細

問題の核心は、src/pkg/sort/sort_test.go 内の countOps 関数で maxswap フィールドに値を設定する以下の行にありました。

maxswap: 1 << 31,

このコードは、maxswap2^31 という値を設定しようとしています。

  • 64ビットシステムの場合: int 型は64ビット幅なので、1 << 312^31 として正しく表現され、問題ありません。2^31 は64ビット符号付き整数の範囲内に収まります。

  • 32ビットシステムの場合: int 型は32ビット幅です。32ビット符号付き整数の最大値は 2^31 - 1 です。1 << 312^31 であり、これは32ビット符号付き整数の表現可能な最大値を超えています。この場合、Goコンパイラは通常、この定数式を int 型に変換しようとしますが、値がオーバーフローするため、結果として負の数(通常は -2^31)として解釈されるか、コンパイルエラーを引き起こす可能性があります。テストコードの文脈では、maxswap が負の値になることで、テストのロジックが意図しない挙動を示す可能性がありました。

この問題を解決するために、コミットでは maxswap の値を以下のように変更しました。

maxswap: 1<<31 - 1,

この変更により、maxswap の値は 2^31 - 1 となります。これは、32ビット符号付き整数の最大値と完全に一致します。これにより、32ビットシステムでもオーバーフローが発生せず、maxswap が正しく最大の正の整数として設定されるようになります。

この修正は、テストコードの堅牢性を高め、Go言語がサポートするすべてのアーキテクチャで一貫したテスト結果を保証するために重要です。

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

変更は src/pkg/sort/sort_test.go ファイルの1箇所のみです。

--- a/src/pkg/sort/sort_test.go
+++ b/src/pkg/sort/sort_test.go
@@ -504,7 +504,7 @@ func countOps(t *testing.T, algo func(Interface), name string) {
 			desc:    name,
 			t:       t,
 			data:    make([]int, n),
-			maxswap: 1 << 31,
+			maxswap: 1<<31 - 1,
 		}
 		for i := 0; i < n; i++ {
 			td.data[i] = rand.Intn(n / 5)

コアとなるコードの解説

変更された行は、countOps 関数内の匿名構造体の初期化部分です。

countOps 関数は、ソートアルゴリズムの操作回数をカウントするためのテストヘルパー関数です。この関数内で、testdata 構造体(td)が初期化されます。testdata 構造体には maxswap というフィールドがあり、これはソート中に許容される最大スワップ回数を表すものと推測されます。

元のコード: maxswap: 1 << 31, これは 2^31maxswap に設定しようとしていました。32ビットシステムでは、この値は符号付き整数の範囲外であり、オーバーフローを引き起こす可能性がありました。

修正後のコード: maxswap: 1<<31 - 1, これは 2^31 - 1maxswap に設定します。この値は、32ビット符号付き整数の最大値であり、すべてのGoがサポートするアーキテクチャで正しく表現できます。これにより、32ビットシステムでのビルドエラーや予期せぬテスト結果が回避されます。

この修正は、Go言語のクロスプラットフォーム互換性を維持し、異なるアーキテクチャ上でのテストの信頼性を確保するために不可欠でした。

関連リンク

参考にした情報源リンク