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

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

このコミットは、Goランタイムのデータ競合検出器(Race Detector)に関連する変更です。具体的には、メモリ範囲へのアクセスを監視する関数 ReadRange および WriteRange から、step パラメータが削除されています。これは、このパラメータがもはや使用されていないため、コードの整理と簡素化を目的としたものです。

コミット

commit e2d95c1f24cd32607458ba5d5bef689f2ee7b00e
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Thu Jun 13 16:38:44 2013 +0400

    runtime/race: remove now unused step parameter from range access functions
    
    R=golang-dev, dave
    CC=golang-dev
    https://golang.org/cl/10259043

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

https://github.com/golang/go/commit/e2d95c1f24cd32607458ba5d5bef689f2ee7b00e

元コミット内容

runtime/race: remove now unused step parameter from range access functions

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/10259043

変更の背景

Goのランタイムには、並行処理におけるデータ競合(data race)を検出するための「Race Detector」が組み込まれています。これは、Googleが開発した動的解析ツールであるThreadSanitizer (TSan) をベースにしています。TSanは、マルチスレッドプログラムにおけるメモリ競合を検出し、デバッグを支援することを目的としています。

このコミットの背景には、Race Detectorの内部実装の進化があります。初期の設計では、メモリ範囲へのアクセスを監視する際に、アクセスされるバイト列のサイズ (sz) に加えて、各要素間のステップサイズ (step) を指定する必要がありました。これは、例えば配列の要素が連続していない場合や、特定のパターンでアクセスされる場合に有用であると考えられていた可能性があります。

しかし、Goランタイムの進化に伴い、ReadRange および WriteRange 関数が呼び出されるコンテキストにおいて、step パラメータが常に特定の固定値(例えば1バイト)であるか、あるいはその情報がもはや競合検出のロジックにとって不要になったと考えられます。このコミットは、その「もはや使用されていない」step パラメータをコードベースから削除し、冗長な引数を排除することで、コードの簡潔性、可読性、および保守性を向上させることを目的としています。

前提知識の解説

データ競合 (Data Race)

データ競合とは、複数のゴルーチン(またはスレッド)が同時に同じメモリ位置にアクセスし、そのうち少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生するバグです。データ競合は、プログラムの非決定的な動作やクラッシュを引き起こす可能性があり、デバッグが非常に困難です。

Go Race Detector

Go言語には、ビルド時に-raceフラグを付けることで有効にできる組み込みのデータ競合検出器があります。これは、プログラムの実行中にメモリアクセスを監視し、データ競合のパターンを検出すると警告を出力します。Go Race Detectorは、GoogleのThreadSanitizer (TSan) をGoランタイムに統合したものです。

ThreadSanitizer (TSan)

ThreadSanitizerは、C++、Goなどの言語で書かれたマルチスレッドプログラムのデータ競合を検出するための動的解析ツールです。TSanは、インストルメンテーション(コードの自動挿入)によってメモリアクセスを追跡し、競合が発生する可能性のあるアクセスパターンを特定します。TSanは、各メモリ位置に対して「シャドウメモリ」と呼ばれる追加のメタデータを保持し、アクセス履歴(読み書き、スレッドID、タイムスタンプなど)を記録します。これにより、競合の検出が可能になります。

runtime/race パッケージ

Goランタイムのruntime/raceパッケージは、Go Race DetectorのC言語およびGo言語による実装を含んでいます。このパッケージ内の関数は、Goプログラムのメモリ操作(読み込み、書き込み、アトミック操作など)をTSanに報告するためのインターフェースを提供します。例えば、runtime·racereadpcruntime·racewriterangepc といった関数は、特定のメモリ領域へのアクセスが発生したことをRace Detectorに通知するために使用されます。

uintptrvoid *

  • uintptr: Go言語におけるポインタを整数として表現するための型です。メモリアドレスを数値として扱う際に使用されます。
  • void *: C言語における汎用ポインタ型です。任意の型のデータへのポインタとして使用できます。GoランタイムのC部分とGo部分の間のインターフェースでよく見られます。

技術的詳細

このコミットの核心は、runtime/raceパッケージ内のReadRangeおよびWriteRange関数からstepパラメータが削除されたことです。

元々の関数シグネチャは以下のようでした(C言語の表記に準ずる):

void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);

変更後:

void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);
void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);

同様に、これらの関数を呼び出す内部のヘルパー関数 rangeaccessstep パラメータを削除しています。

// 変更前
static void rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc, bool write)

// 変更後
static void rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)

この変更が意味するのは、stepパラメータがRace Detectorの内部ロジックにおいて、もはや意味のある情報として利用されていなかったということです。通常、stepパラメータは、配列やスライスのような連続したメモリ領域に対して、要素が特定のバイトサイズで区切られている場合に、その区切りサイズを示すために使用されます。例えば、int32の配列であればstepは4バイト、byteの配列であればstepは1バイトとなります。

しかし、TSanのようなツールは、通常、個々のメモリアクセスを監視し、そのアクセスがどのメモリ範囲に属するかを判断します。ReadRangeWriteRangeが呼び出される際には、既にアクセスされるメモリの開始アドレス(addr)と合計サイズ(sz)が分かっているため、個々の要素のステップサイズは競合検出のアルゴリズムにとって直接的な影響を与えないか、あるいは他の方法で推論できるようになったと考えられます。

コミットの差分を見ると、src/pkg/runtime/race/race.go内のGo側のReadRangeWriteRangeの実装では、C.__tsan_read_rangeC.__tsan_write_rangeを呼び出す際に、step引数に0 /*step is unused*/というコメント付きで0を渡しています。これは、C側のTSanインターフェースがまだstep引数を期待しているものの、Go側からはその値が意味を持たないことを示唆しています。このコミットは、Goランタイムの内部関数からこの冗長な引数を削除し、TSanへの呼び出し時に固定値(0)を渡すことで、Go側のコードをクリーンアップしています。

この変更は、Goランタイムの内部的な最適化とコードの整理の一環であり、Goプログラムの外部動作やRace Detectorの検出能力に直接的な影響を与えるものではありません。しかし、ランタイムのコードベースがより簡潔になり、将来的なメンテナンスが容易になるというメリットがあります。

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

このコミットでは、主に以下のファイルでstepパラメータの削除とそれに伴う呼び出し箇所の修正が行われています。

  • src/pkg/runtime/race.c: ReadRange, WriteRange関数の宣言と定義、およびrangeaccessヘルパー関数のシグネチャからstepパラメータを削除。runtime·racewriterangepcruntime·racereadrangepcの呼び出し箇所も修正。
  • src/pkg/runtime/race.h: ReadRange, WriteRange関数のプロトタイプ宣言からstepパラメータを削除。
  • src/pkg/runtime/race/race.go: Go側のReadRange, WriteRange関数のシグネチャからstepパラメータを削除。内部でC側のTSan関数を呼び出す際に、step引数に0を渡すように変更。
  • src/pkg/runtime/race0.c: Race Detectorが無効な場合のダミー関数runtime·racewriterangepcruntime·racereadrangepcからstepパラメータを削除。
  • src/pkg/runtime/slice.c: runtime·appendslice, runtime·appendstr, runtime·growslice, runtime·copy, runtime·slicestringcopyといったスライス操作関連の関数内でruntime·racereadrangepcruntime·racewriterangepcを呼び出している箇所からstep引数を削除。
  • src/pkg/runtime/string.goc: slicebytetostring, slicerunetostringといった文字列変換関連の関数内でruntime·racereadrangepcを呼び出している箇所からstep引数を削除。

コアとなるコードの解説

以下に、主要な変更箇所のコードスニペットと解説を示します。

src/pkg/runtime/race.c

--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -16,8 +16,8 @@ void runtime∕race·Finalize(void);
 void runtime∕race·FinalizerGoroutine(uintptr racectx);\n void runtime∕race·Read(uintptr racectx, void *addr, void *pc);\n void runtime∕race·Write(uintptr racectx, void *addr, void *pc);\n-void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);\n-void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);\n+void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);\n+void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);\n void runtime∕race·FuncEnter(uintptr racectx, void *pc);\n void runtime∕race·FuncExit(uintptr racectx);\n void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);\
@@ -189,7 +189,7 @@ runtime·racereadpc(void *addr, void *callpc, void *pc)\n }\n \n static void\n-rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc, bool write)\n+rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)\n {\n \tuintptr racectx;\n \n@@ -202,9 +202,9 @@ rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc,\n \t\t\truntime∕race·FuncEnter(racectx, (void*)callpc);\n \t\t}\n \t\tif(write)\n-\t\t\truntime∕race·WriteRange(racectx, addr, size, step, (void*)pc);\n+\t\t\truntime∕race·WriteRange(racectx, addr, size, (void*)pc);\n \t\telse\n-\t\t\truntime∕race·ReadRange(racectx, addr, size, step, (void*)pc);\n+\t\t\truntime∕race·ReadRange(racectx, addr, size, (void*)pc);\n \t\tif(callpc)\n \t\t\truntime∕race·FuncExit(racectx);\n \t\tm->racecall = false;\
@@ -212,15 +212,15 @@ rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc,\n }\n \n void\n-runtime·racewriterangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)\n+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)\n {\n-\trangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, true);\n+\trangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);\n }\n \n void\n-runtime·racereadrangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)\n+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)\n {\n-\trangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, false);\n+\trangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, false);\n }\n \n void\n@@ -335,7 +335,7 @@ runtime·RaceWrite(void *addr)\n void\n runtime·RaceReadRange(void *addr, intgo len)\n {\n-\trangeaccess(addr, len, 1, 0, (uintptr)runtime·getcallerpc(&addr), false);\n+\trangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), false);\n }\n \n // func RaceWriteRange(addr unsafe.Pointer, len int)\n@@ -343,7 +343,7 @@ runtime·RaceReadRange(void *addr, intgo len)\n void\n runtime·RaceWriteRange(void *addr, intgo len)\n {\n-\trangeaccess(addr, len, 1, 0, (uintptr)runtime·getcallerpc(&addr), true);\n+\trangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), true);\n }\n \n // func RaceDisable()\n```
-   `runtime∕race·ReadRange` と `runtime∕race·WriteRange` の関数宣言と定義から `uintptr step` が削除されています。
-   内部ヘルパー関数 `rangeaccess` のシグネチャからも `uintptr step` が削除されています。
-   `runtime·racewriterangepc` と `runtime·racereadrangepc` の定義も同様に `step` パラメータが削除され、内部の `rangeaccess` 呼び出しも修正されています。
-   `runtime·RaceReadRange` と `runtime·RaceWriteRange` の呼び出し箇所では、以前 `1` が渡されていた `step` 引数が `0` に変更されています。これは、Go側の`race.go`での変更と整合しています。

### `src/pkg/runtime/race/race.go`

```diff
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -56,14 +56,14 @@ func Write(racectx uintptr, addr, pc uintptr) {\n \tC.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))\n }\n \n-func ReadRange(racectx uintptr, addr, sz, step, pc uintptr) {\n+func ReadRange(racectx uintptr, addr, sz, pc uintptr) {\n \tC.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),\n-\t\tC.long(sz), C.long(step), unsafe.Pointer(pc))\n+\t\tC.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))\n }\n \n-func WriteRange(racectx uintptr, addr, sz, step, pc uintptr) {\n+func WriteRange(racectx uintptr, addr, sz, pc uintptr) {\n \tC.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),\n-\t\tC.long(sz), C.long(step), unsafe.Pointer(pc))\n+\t\tC.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))\n }\n \n func FuncEnter(racectx uintptr, pc uintptr) {\
  • Go側の ReadRangeWriteRange 関数のシグネチャから step uintptr が削除されています。
  • C.__tsan_read_range および C.__tsan_write_range を呼び出す際、以前 C.long(step) が渡されていた箇所が 0 /*step is unused*/ に変更されています。これは、C側のTSanインターフェースがまだstep引数を期待しているものの、Go側からはその値が意味を持たないことを明確に示しています。

src/pkg/runtime/slice.c および src/pkg/runtime/string.goc

これらのファイルでは、スライスや文字列操作に関連するGoランタイム関数が、runtime·racereadrangepcruntime·racewriterangepc を呼び出す際に、step 引数を渡していた箇所が削除されています。例えば、runtime·appendslice の変更は以下のようになります。

--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -82,12 +82,12 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)\n \t\tpc = runtime·getcallerpc(&t);\n \t\t// read x[:len]\n \t\tif(m > x.cap)\n-\t\t\truntime·racereadrangepc(x.array, x.len*w, w, pc, runtime·appendslice);\n+\t\t\truntime·racereadrangepc(x.array, x.len*w, pc, runtime·appendslice);\n \t\t// read y\n-\t\truntime·racereadrangepc(y.array, y.len*w, w, pc, runtime·appendslice);\n+\t\truntime·racereadrangepc(y.array, y.len*w, pc, runtime·appendslice);\n \t\t// write x[len(x):len(x)+len(y)]\n \t\tif(m <= x.cap)\n-\t\t\truntime·racewriterangepc(ret.array+ret.len*w, y.len*w, w, pc, runtime·appendslice);\n+\t\t\truntime·racewriterangepc(ret.array+ret.len*w, y.len*w, pc, runtime·appendslice);\n \t}\n```
-   `runtime·racereadrangepc` および `runtime·racewriterangepc` の呼び出しから、`w` (要素の幅、つまりステップサイズ) を表す引数が削除されています。これは、`step` パラメータが不要になったことの具体的な適用例です。

これらの変更は、`step` パラメータがGo Race Detectorの内部ロジックにおいて冗長になったことを示しており、コードベースのクリーンアップと簡素化に貢献しています。

## 関連リンク

-   Go Race Detector: [https://go.dev/doc/articles/race_detector](https://go.dev/doc/articles/race_detector)
-   ThreadSanitizer: [https://clang.llvm.org/docs/ThreadSanitizer.html](https://clang.llvm.org/docs/ThreadSanitizer.html)
-   Go Change List 10259043: [https://golang.org/cl/10259043](https://golang.org/cl/10259043) (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)

## 参考にした情報源リンク

-   Go Race Detector Documentation
-   ThreadSanitizer Documentation
-   Go Source Code (特に `src/pkg/runtime/race` ディレクトリ)
-   Go言語の公式ドキュメント
-   コミットメッセージと差分情報
-   Go言語のメーリングリストやIssueトラッカー(関連する議論がある場合)
-   Go言語のランタイムに関する技術記事やブログポスト
-   Go言語の内部実装に関する書籍や資料
-   Goの`unsafe`パッケージに関するドキュメント(`unsafe.Pointer`の理解のため)
-   C言語のポインタと型変換に関する一般的な知識# [インデックス 16566] ファイルの概要

このコミットは、Goランタイムのデータ競合検出器(Race Detector)に関連する変更です。具体的には、メモリ範囲へのアクセスを監視する関数 `ReadRange` および `WriteRange` から、`step` パラメータが削除されています。これは、このパラメータがもはや使用されていないため、コードの整理と簡素化を目的としたものです。

## コミット

commit e2d95c1f24cd32607458ba5d5bef689f2ee7b00e Author: Dmitriy Vyukov dvyukov@google.com Date: Thu Jun 13 16:38:44 2013 +0400

runtime/race: remove now unused step parameter from range access functions

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/10259043

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

[https://github.com/golang/go/commit/e2d95c1f24cd32607458ba5d5bef689f2ee7b00e](https://github.com/golang/go/commit/e2d95c1f24cd32607458ba5d5bef689f2ee7b00e)

## 元コミット内容

runtime/race: remove now unused step parameter from range access functions

R=golang-dev, dave CC=golang-dev https://golang.org/cl/10259043


## 変更の背景

Goのランタイムには、並行処理におけるデータ競合(data race)を検出するための「Race Detector」が組み込まれています。これは、Googleが開発した動的解析ツールであるThreadSanitizer (TSan) をベースにしています。TSanは、マルチスレッドプログラムにおけるメモリ競合を検出し、デバッグを支援することを目的としています。

このコミットの背景には、Race Detectorの内部実装の進化があります。初期の設計では、メモリ範囲へのアクセスを監視する際に、アクセスされるバイト列のサイズ (`sz`) に加えて、各要素間のステップサイズ (`step`) を指定する必要がありました。これは、例えば配列の要素が連続していない場合や、特定のパターンでアクセスされる場合に有用であると考えられていた可能性があります。

しかし、Goランタイムの進化に伴い、`ReadRange` および `WriteRange` 関数が呼び出されるコンテキストにおいて、`step` パラメータが常に特定の固定値(例えば1バイト)であるか、あるいはその情報がもはや競合検出のロジックにとって不要になったと考えられます。このコミットは、その「もはや使用されていない」`step` パラメータをコードベースから削除し、冗長な引数を排除することで、コードの簡潔性、可読性、および保守性を向上させることを目的としています。

## 前提知識の解説

### データ競合 (Data Race)

データ競合とは、複数のゴルーチン(またはスレッド)が同時に同じメモリ位置にアクセスし、そのうち少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生するバグです。データ競合は、プログラムの非決定的な動作やクラッシュを引き起こす可能性があり、デバッグが非常に困難です。

### Go Race Detector

Go言語には、ビルド時に`-race`フラグを付けることで有効にできる組み込みのデータ競合検出器があります。これは、プログラムの実行中にメモリアクセスを監視し、データ競合のパターンを検出すると警告を出力します。Go Race Detectorは、GoogleのThreadSanitizer (TSan) をGoランタイムに統合したものです。

### ThreadSanitizer (TSan)

ThreadSanitizerは、C++、Goなどの言語で書かれたマルチスレッドプログラムのデータ競合を検出するための動的解析ツールです。TSanは、インストルメンテーション(コードの自動挿入)によってメモリアクセスを追跡し、競合が発生する可能性のあるアクセスパターンを特定します。TSanは、各メモリ位置に対して「シャドウメモリ」と呼ばれる追加のメタデータを保持し、アクセス履歴(読み書き、スレッドID、タイムスタンプなど)を記録します。これにより、競合の検出が可能になります。

### `runtime/race` パッケージ

Goランタイムの`runtime/race`パッケージは、Go Race DetectorのC言語およびGo言語による実装を含んでいます。このパッケージ内の関数は、Goプログラムのメモリ操作(読み込み、書き込み、アトミック操作など)をTSanに報告するためのインターフェースを提供します。例えば、`runtime·racereadpc` や `runtime·racewriterangepc` といった関数は、特定のメモリ領域へのアクセスが発生したことをRace Detectorに通知するために使用されます。

### `uintptr` と `void *`

-   `uintptr`: Go言語におけるポインタを整数として表現するための型です。メモリアドレスを数値として扱う際に使用されます。
-   `void *`: C言語における汎用ポインタ型です。任意の型のデータへのポインタとして使用できます。GoランタイムのC部分とGo部分の間のインターフェースでよく見られます。

## 技術的詳細

このコミットの核心は、`runtime/race`パッケージ内の`ReadRange`および`WriteRange`関数から`step`パラメータが削除されたことです。

元々の関数シグネチャは以下のようでした(C言語の表記に準ずる):

```c
void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);
void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);

変更後:

void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);
void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);

同様に、これらの関数を呼び出す内部のヘルパー関数 rangeaccessstep パラメータを削除しています。

// 変更前
static void rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc, bool write)

// 変更後
static void rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)

この変更が意味するのは、stepパラメータがRace Detectorの内部ロジックにおいて、もはや意味のある情報として利用されていなかったということです。通常、stepパラメータは、配列やスライスのような連続したメモリ領域に対して、要素が特定のバイトサイズで区切られている場合に、その区切りサイズを示すために使用されます。例えば、int32の配列であればstepは4バイト、byteの配列であればstepは1バイトとなります。

しかし、TSanのようなツールは、通常、個々のメモリアクセスを監視し、そのアクセスがどのメモリ範囲に属するかを判断します。ReadRangeWriteRangeが呼び出される際には、既にアクセスされるメモリの開始アドレス(addr)と合計サイズ(sz)が分かっているため、個々の要素のステップサイズは競合検出のアルゴリズムにとって直接的な影響を与えないか、あるいは他の方法で推論できるようになったと考えられます。

コミットの差分を見ると、src/pkg/runtime/race/race.go内のGo側のReadRangeWriteRangeの実装では、C.__tsan_read_rangeC.__tsan_write_rangeを呼び出す際に、step引数に0 /*step is unused*/というコメント付きで0を渡しています。これは、C側のTSanインターフェースがまだstep引数を期待しているものの、Go側からはその値が意味を持たないことを示唆しています。このコミットは、Goランタイムの内部関数からこの冗長な引数を削除し、TSanへの呼び出し時に固定値(0)を渡すことで、Go側のコードをクリーンアップしています。

この変更は、Goランタイムの内部的な最適化とコードの整理の一環であり、Goプログラムの外部動作やRace Detectorの検出能力に直接的な影響を与えるものではありません。しかし、ランタイムのコードベースがより簡潔になり、将来的なメンテナンスが容易になるというメリットがあります。

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

このコミットでは、主に以下のファイルでstepパラメータの削除とそれに伴う呼び出し箇所の修正が行われています。

  • src/pkg/runtime/race.c: ReadRange, WriteRange関数の宣言と定義、およびrangeaccessヘルパー関数のシグネチャからstepパラメータを削除。runtime·racewriterangepcruntime·racereadrangepcの呼び出し箇所も修正。
  • src/pkg/runtime/race.h: ReadRange, WriteRange関数のプロトタイプ宣言からstepパラメータを削除。
  • src/pkg/runtime/race/race.go: Go側のReadRange, WriteRange関数のシグネチャからstepパラメータを削除。内部でC側のTSan関数を呼び出す際に、step引数に0を渡すように変更。
  • src/pkg/runtime/race0.c: Race Detectorが無効な場合のダミー関数runtime·racewriterangepcruntime·racereadrangepcからstepパラメータを削除。
  • src/pkg/runtime/slice.c: runtime·appendslice, runtime·appendstr, runtime·growslice, runtime·copy, runtime·slicestringcopyといったスライス操作関連の関数内でruntime·racereadrangepcruntime·racewriterangepcを呼び出している箇所からstep引数を削除。
  • src/pkg/runtime/string.goc: slicebytetostring, slicerunetostringといった文字列変換関連の関数内でruntime·racereadrangepcを呼び出している箇所からstep引数を削除。

コアとなるコードの解説

以下に、主要な変更箇所のコードスニペットと解説を示します。

src/pkg/runtime/race.c

--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -16,8 +16,8 @@ void runtime∕race·Finalize(void);
 void runtime∕race·FinalizerGoroutine(uintptr racectx);\n void runtime∕race·Read(uintptr racectx, void *addr, void *pc);\n void runtime∕race·Write(uintptr racectx, void *addr, void *pc);\n-void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);\n-void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, uintptr step, void *pc);\n+void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);\n+void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);\n void runtime∕race·FuncEnter(uintptr racectx, void *pc);\n void runtime∕race·FuncExit(uintptr racectx);\n void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);\
@@ -189,7 +189,7 @@ runtime·racereadpc(void *addr, void *callpc, void *pc)\n }\n \n static void\n-rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc, bool write)\n+rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)\n {\n \tuintptr racectx;\n \n@@ -202,9 +202,9 @@ rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc,\n \t\t\truntime∕race·FuncEnter(racectx, (void*)callpc);\n \t\t}\n \t\tif(write)\n-\t\t\truntime∕race·WriteRange(racectx, addr, size, step, (void*)pc);\n+\t\t\truntime∕race·WriteRange(racectx, addr, size, (void*)pc);\n \t\telse\n-\t\t\truntime∕race·ReadRange(racectx, addr, size, step, (void*)pc);\n+\t\t\truntime∕race·ReadRange(racectx, addr, size, (void*)pc);\n \t\tif(callpc)\n \t\t\truntime∕race·FuncExit(racectx);\n \t\tm->racecall = false;\
@@ -212,15 +212,15 @@ rangeaccess(void *addr, uintptr size, uintptr step, uintptr callpc, uintptr pc,\n }\n \n void\n-runtime·racewriterangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)\n+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)\n {\n-\trangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, true);\n+\trangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);\n }\n \n void\n-runtime·racereadrangepc(void *addr, uintptr sz, uintptr step, void *callpc, void *pc)\n+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)\n {\n-\trangeaccess(addr, sz, step, (uintptr)callpc, (uintptr)pc, false);\n+\trangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, false);\n }\n \n void\n@@ -335,7 +335,7 @@ runtime·RaceWrite(void *addr)\n void\n runtime·RaceReadRange(void *addr, intgo len)\n {\n-\trangeaccess(addr, len, 1, 0, (uintptr)runtime·getcallerpc(&addr), false);\n+\trangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), false);\n }\n \n // func RaceWriteRange(addr unsafe.Pointer, len int)\n@@ -343,7 +343,7 @@ runtime·RaceReadRange(void *addr, intgo len)\n void\n runtime·RaceWriteRange(void *addr, intgo len)\n {\n-\trangeaccess(addr, len, 1, 0, (uintptr)runtime·getcallerpc(&addr), true);\n+\trangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), true);\n }\n \n // func RaceDisable()\n```
-   `runtime∕race·ReadRange` と `runtime∕race·WriteRange` の関数宣言と定義から `uintptr step` が削除されています。
-   内部ヘルパー関数 `rangeaccess` のシグネチャからも `uintptr step` が削除されています。
-   `runtime·racewriterangepc` と `runtime·racereadrangepc` の定義も同様に `step` パラメータが削除され、内部の `rangeaccess` 呼び出しも修正されています。
-   `runtime·RaceReadRange` と `runtime·RaceWriteRange` の呼び出し箇所では、以前 `1` が渡されていた `step` 引数が `0` に変更されています。これは、Go側の`race.go`での変更と整合しています。

### `src/pkg/runtime/race/race.go`

```diff
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -56,14 +56,14 @@ func Write(racectx uintptr, addr, pc uintptr) {\n \tC.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))\n }\n \n-func ReadRange(racectx uintptr, addr, sz, step, pc uintptr) {\n+func ReadRange(racectx uintptr, addr, sz, pc uintptr) {\n \tC.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),\n-\t\tC.long(sz), C.long(step), unsafe.Pointer(pc))\n+\t\tC.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))\n }\n \n-func WriteRange(racectx uintptr, addr, sz, step, pc uintptr) {\n+func WriteRange(racectx uintptr, addr, sz, pc uintptr) {\n \tC.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),\n-\t\tC.long(sz), C.long(step), unsafe.Pointer(pc))\n+\t\tC.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))\n }\n \n func FuncEnter(racectx uintptr, pc uintptr) {\
  • Go側の ReadRangeWriteRange 関数のシグネチャから step uintptr が削除されています。
  • C.__tsan_read_range および C.__tsan_write_range を呼び出す際、以前 C.long(step) が渡されていた箇所が 0 /*step is unused*/ に変更されています。これは、C側のTSanインターフェースがまだstep引数を期待しているものの、Go側からはその値が意味を持たないことを明確に示しています。

src/pkg/runtime/slice.c および src/pkg/runtime/string.goc

これらのファイルでは、スライスや文字列操作に関連するGoランタイム関数が、runtime·racereadrangepcruntime·racewriterangepc を呼び出す際に、step 引数を渡していた箇所が削除されています。例えば、runtime·appendslice の変更は以下のようになります。

--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -82,12 +82,12 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)\n \t\tpc = runtime·getcallerpc(&t);\n \t\t// read x[:len]\n \t\tif(m > x.cap)\n-\t\t\truntime·racereadrangepc(x.array, x.len*w, w, pc, runtime·appendslice);\n+\t\t\truntime·racereadrangepc(x.array, x.len*w, pc, runtime·appendslice);\n \t\t// read y\n-\t\truntime·racereadrangepc(y.array, y.len*w, w, pc, runtime·appendslice);\n+\t\truntime·racereadrangepc(y.array, y.len*w, pc, runtime·appendslice);\n \t\t// write x[len(x):len(x)+len(y)]\n \t\tif(m <= x.cap)\n-\t\t\truntime·racewriterangepc(ret.array+ret.len*w, y.len*w, w, pc, runtime·appendslice);\n+\t\t\truntime·racewriterangepc(ret.array+ret.len*w, y.len*w, pc, runtime·appendslice);\n \t}\n```
-   `runtime·racereadrangepc` および `runtime·racewriterangepc` の呼び出しから、`w` (要素の幅、つまりステップサイズ) を表す引数が削除されています。これは、`step` パラメータが不要になったことの具体的な適用例です。

これらの変更は、`step` パラメータがGo Race Detectorの内部ロジックにおいて冗長になったことを示しており、コードベースのクリーンアップと簡素化に貢献しています。

## 関連リンク

-   Go Race Detector: [https://go.dev/doc/articles/race_detector](https://go.dev/doc/articles/race_detector)
-   ThreadSanitizer: [https://clang.llvm.org/docs/ThreadSanitizer.html](https://clang.llvm.org/docs/ThreadSanitizer.html)
-   Go Change List 10259043: [https://golang.org/cl/10259043](https://golang.org/cl/10259043) (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)

## 参考にした情報源リンク

-   Go Race Detector Documentation
-   ThreadSanitizer Documentation
-   Go Source Code (特に `src/pkg/runtime/race` ディレクトリ)
-   Go言語の公式ドキュメント
-   コミットメッセージと差分情報
-   Go言語のメーリングリストやIssueトラッカー(関連する議論がある場合)
-   Go言語のランタイムに関する技術記事やブログポスト
-   Go言語の内部実装に関する書籍や資料
-   Goの`unsafe`パッケージに関するドキュメント(`unsafe.Pointer`の理解のため)
-   C言語のポインタと型変換に関する一般的な知識