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

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

このコミットは、Go言語のAPI定義ファイルである api/go1.txt に、Linux/ARMアーキテクチャ向けのAPIを追加するものです。特に、syscall パッケージ内の RawSockaddr 構造体の Data フィールドの型が、他のプラットフォームでは [14]int8 であるのに対し、Linux/ARMでは [14]uint8 となっているという、型定義の不一致を修正・明記することが主な目的です。

コミット

commit 5612fd770dcf0d89a43bcb01713805883493a3e4
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Mon Jun 4 15:21:58 2012 +0800

    api: add Linux/ARM to go1 API
    It's very unfortunate that the type of Data field of struct
    RawSockaddr is [14]uint8 on Linux/ARM instead of [14]int8
    on all the others.
    btw, it should be [14]int8 according to my header files.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/6275050

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

https://github.com/golang/go/commit/5612fd770dcf0d89a43bcb01713805883493a3e4

元コミット内容

Go 1 APIにLinux/ARMアーキテクチャを追加する。 RawSockaddr 構造体の Data フィールドの型が、Linux/ARMでは [14]uint8 であるのに対し、他の全てのプラットフォームでは [14]int8 であることは非常に残念である。 ちなみに、私のヘッダーファイルによれば、[14]int8 であるべきだ。

変更の背景

Go言語は、その設計思想の一つとして「安定したAPI」を非常に重視しています。特にGo 1リリースにおいては、将来にわたって互換性を保証する「Go 1 Compatibility Promise」が掲げられ、そのAPIセットは go1.txt というファイルで厳密に管理されていました。

このコミットが行われた2012年6月は、Go 1の正式リリース(2012年3月)から間もない時期であり、Go言語が様々なプラットフォームで安定して動作するための調整が活発に行われていました。Linux/ARMは当時、組み込みシステムやモバイルデバイスで普及し始めていた重要なアーキテクチャであり、Go言語がこれらの環境で利用されるためには、そのAPIがGo 1の互換性保証の対象となる必要がありました。

本コミットの具体的な背景は、Linux/ARM環境における syscall パッケージの RawSockaddr 構造体の Data フィールドの型定義が、他のアーキテクチャ(例えば darwin-386, darwin-amd64, freebsd-386, freebsd-amd64, linux-386, linux-amd64 など)と異なっていた点にあります。他のアーキテクチャでは [14]int8 と定義されているにもかかわらず、Linux/ARMでは [14]uint8 となっていました。これは、Go言語の syscall パッケージが、各OSおよびアーキテクチャ固有のシステムコールやデータ構造をGoの型にマッピングする際に発生する差異の一つです。

この型不一致は、Go 1 APIの互換性保証の観点から問題となります。Go 1 APIは、特定のプラットフォームに依存しない形でGoプログラムが動作することを保証するため、可能な限りプラットフォーム間の差異を吸収し、統一されたインターフェースを提供することを目指しています。しかし、RawSockaddr.Data のような低レベルな構造体の型が異なると、クロスプラットフォーム開発において予期せぬ挙動やバグを引き起こす可能性があります。

コミットメッセージにある「btw, it should be [14]int8 according to my header files.」という記述は、コミッターが参照したLinux/ARMのC言語ヘッダーファイルでは int8 に相当する型が使われているにもかかわらず、Goのビルドシステムやツールチェーンが uint8 と解釈してしまっていた可能性を示唆しています。これは、Goの syscall パッケージがCのヘッダーファイルを解析してGoの型定義を生成するプロセス(go tool cgogo tool api などが関与)における、特定のアーキテクチャでのエッジケースであったと考えられます。

このコミットは、この差異を go1.txt に明記することで、Linux/ARM環境における syscall パッケージのAPIがGo 1の互換性保証の対象となることを公式に宣言し、開発者がこのプラットフォームでGoプログラムを安心して利用できるようにするための重要なステップでした。

前提知識の解説

Go 1 Compatibility Promiseと go1.txt

Go言語は、バージョン1.0のリリース時に「Go 1 Compatibility Promise」という重要な方針を発表しました。これは、Go 1でリリースされたAPIは、Go 1.xの全てのバージョンにおいて互換性が維持されることを保証するものです。これにより、Go開発者は将来のGoバージョンアップによって既存のコードが動かなくなる心配をせずに、安心してGo言語を利用できるようになりました。

この互換性保証の具体的な対象となるAPIは、Goのソースコードリポジトリ内の api/go1.txt というファイルに厳密に定義されています。このファイルには、Go標準ライブラリの全ての公開API(パッケージ、型、関数、メソッド、定数、変数など)が、プラットフォームごとに列挙されています。Goのビルドプロセスでは、この go1.txt に記載されたAPIと実際のコードが一致しているかどうかが検証され、不一致があればビルドエラーとなります。これにより、意図しないAPIの変更が防がれ、互換性が維持されます。

syscall パッケージ

syscall パッケージは、Go言語からOSのシステムコールを直接呼び出すための低レベルなインターフェースを提供します。ファイル操作、ネットワーク通信、プロセス管理など、OSが提供する基本的な機能の多くはシステムコールを通じて行われます。

syscall パッケージは、OSやアーキテクチャに強く依存する特性を持っています。例えば、LinuxとWindowsではシステムコールの名前や引数が異なり、同じLinuxでもx86とARMではレジスタの扱いなどが異なります。そのため、syscall パッケージは、各プラットフォーム固有の定数、構造体、関数などを定義しており、これらはビルド時にターゲットとなるOSとアーキテクチャに応じて選択的にコンパイルされます。

RawSockaddr 構造体

RawSockaddrsyscall パッケージで定義される構造体の一つで、ソケットアドレスの生データ(raw data)を表現するために使用されます。ソケットアドレスは、ネットワーク通信において接続先や接続元の情報を識別するために使われるデータ構造で、IPアドレスやポート番号などが含まれます。

RawSockaddr は、特定のソケットアドレスファミリー(例: IPv4, IPv6, Unixドメインソケットなど)に依存しない汎用的な形式でソケットアドレスを扱う際に利用されます。通常、この構造体は Family フィールドでアドレスファミリーの種類を示し、Data フィールドで実際のソケットアドレスのバイナリデータを保持します。Data フィールドは、OSやアドレスファミリーによってその内容が異なるため、通常はバイト配列として定義されます。

int8uint8 の違い

int8 は符号付き8ビット整数型で、-128から127までの値を表現できます。一方、uint8 は符号なし8ビット整数型で、0から255までの値を表現できます。

低レベルなバイナリデータを扱う場合、特にC言語との相互運用においては、これらの型の選択が重要になります。C言語の char 型は、コンパイラやプラットフォームによって符号付き (signed char) または符号なし (unsigned char) のどちらとして扱われるかが異なります。Goの syscall パッケージがCのヘッダーファイルを解析してGoの型を生成する際、Cの charint8uint8 のどちらにマッピングされるかは、そのプラットフォームのCコンパイラのデフォルト設定や、Goのツールチェーンが採用しているヒューリスティックに依存します。

RawSockaddr.Data のような生データの場合、そのバイト列が符号付きの数値として解釈されるか、符号なしの数値として解釈されるかによって、データの意味合いが変わる可能性があります。特に、ネットワークプロトコルによっては、特定のバイトが符号付きの値として扱われることがあるため、型の一致はデータの正確な解釈に不可欠です。

技術的詳細

このコミットの技術的な核心は、Goの syscall パッケージがLinux/ARMアーキテクチャ向けに RawSockaddr 構造体を生成する際の、Data フィールドの型推論またはマッピングの差異にあります。

Goの syscall パッケージは、各OSおよびアーキテクチャのシステムコールインターフェースをGoの型システムに適合させるために、C言語のヘッダーファイルから情報を抽出してGoのコードを生成するプロセスを利用しています。このプロセスは、go tool cgogo tool api といったツールによって支援されます。

問題となった RawSockaddr 構造体は、C言語の struct sockaddr やその派生構造体(struct sockaddr_in, struct sockaddr_in6 など)に対応します。これらの構造体は、通常、アドレスファミリーを示すフィールドと、それに続くアドレスデータを含むバイト配列で構成されます。C言語では、このアドレスデータ部分が char 型の配列として定義されることが一般的です。

例えば、一般的なLinuxのCヘッダーファイルでは、struct sockaddr は以下のように定義されていることがあります(簡略化された例):

struct sockaddr {
    sa_family_t sa_family; // アドレスファミリー
    char sa_data[14];      // ソケットアドレスデータ
};

ここで sa_datachar 型の配列です。C言語の標準では charsigned charunsigned char のどちらであるかは実装定義です。多くのシステムでは signed char として扱われますが、一部のシステムやコンパイラ設定では unsigned char となることがあります。

GoのツールチェーンがLinux/ARMのCヘッダーファイルを解析した際、何らかの理由で char sa_data[14][14]uint8(Goにおける unsigned char に相当)としてマッピングされてしまったと考えられます。これは、GoのツールチェーンがLinux/ARM環境のCコンパイラのデフォルトの char の解釈を unsigned と判断したか、あるいは特定のARM固有のABI(Application Binary Interface)やコンパイラ設定が影響した可能性があります。

他のアーキテクチャでは [14]int8(Goにおける signed char に相当)としてマッピングされていたため、このLinux/ARMでの [14]uint8 という差異は、Go 1 APIの互換性保証の観点から問題視されました。Go 1 APIは、可能な限りプラットフォーム間で統一された型を提供することを目指しており、このような低レベルな構造体の型不一致は、クロスプラットフォームで syscall パッケージを利用するGoプログラムに影響を与える可能性があるためです。

このコミットは、この差異を api/go1.txt に明示的に追加することで、Linux/ARMにおける RawSockaddr.Data の型が [14]uint8 であることをGo 1 APIの一部として公式に認め、将来にわたってこの型が維持されることを保証するものです。これにより、Go開発者はLinux/ARM環境で syscall パッケージを使用する際に、この特定の型定義を考慮に入れることができるようになります。

また、この変更は src/cmd/api/goapi.go にも影響を与えています。goapi.gogo1.txt を生成・検証するためのツールであり、新しいアーキテクチャのAPI定義を追加する際には、このツールが正しく動作するように調整が必要となります。具体的には、Linux/ARM向けのAPI定義を go1.txt に追加する際に、goapi.go がその変更を正しく処理できるように、内部的なロジックやデータ構造が更新された可能性があります。

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

このコミットの主要な変更は、api/go1.txt ファイルに対するものです。

--- a/api/go1.txt
+++ b/api/go1.txt
@@ -4053,6 +4053,29 @@ pkg log/syslog (linux-amd64-cgo), method (*Writer) Warning(string) error
 pkg log/syslog (linux-amd64-cgo), method (*Writer) Write([]byte) (int, error)
 pkg log/syslog (linux-amd64-cgo), type Priority int
 pkg log/syslog (linux-amd64-cgo), type Writer struct
+pkg log/syslog (linux-arm), const LOG_ALERT Priority
+pkg log/syslog (linux-arm), const LOG_CRIT Priority
+pkg log/syslog (linux-arm), const LOG_DEBUG Priority
+pkg log/syslog (linux-arm), const LOG_EMERG Priority
+pkg log/syslog (linux-arm), const LOG_ERR Priority
+pkg log/syslog (linux-arm), const LOG_INFO Priority
+pkg log/syslog (linux-arm), const LOG_NOTICE Priority
+pkg log/syslog (linux-arm), const LOG_WARNING Priority
+pkg log/syslog (linux-arm), func Dial(string, Priority, string) (*Writer, error)
+pkg log/syslog (linux-arm), func New(Priority, string) (*Writer, error)
+pkg log/syslog (linux-arm), func NewLogger(Priority, int) (*log.Logger, error)
+pkg log/syslog (linux-arm), method (*Writer) Alert(string) error
+pkg log/syslog (linux-arm), method (*Writer) Close() error
+pkg log/syslog (linux-arm), method (*Writer) Crit(string) error
+pkg log/syslog (linux-arm), method (*Writer) Debug(string) error
+pkg log/syslog (linux-arm), method (*Writer) Emerg(string) error
+pkg log/syslog (linux-arm), method (*Writer) Err(string) error
+pkg log/syslog (linux-arm), method (*Writer) Info(string) error
+pkg log/syslog (linux-arm), method (*Writer) Notice(string) error
+pkg log/syslog (linux-arm), method (*Writer) Warning(string) error
+pkg log/syslog (linux-arm), method (*Writer) Write([]byte) (int, error)
+pkg log/syslog (linux-arm), type Priority int
+pkg log/syslog (linux-arm), type Writer struct
 pkg math, const E ideal-float
 pkg math, const Ln10 ideal-float
 pkg math, const Ln2 ideal-float
@@ -7552,6 +7575,7 @@ pkg syscall (darwin-386), type Msghdr struct, Namelen uint32
 pkg syscall (darwin-386), type Radvisory_t struct
 pkg syscall (darwin-386), type Radvisory_t struct, Count int32
 pkg syscall (darwin-386), type Radvisory_t struct, Offset int64
+pkg syscall (darwin-386), type RawSockaddr struct, Data [14]int8
 pkg syscall (darwin-386), type RawSockaddr struct, Family uint8
 pkg syscall (darwin-386), type RawSockaddr struct, Len uint8
 pkg syscall (darwin-386), type RawSockaddrAny struct, Pad [92]int8
@@ -9370,6 +9394,7 @@ pkg syscall (darwin-386-cgo), type Msghdr struct, Namelen uint32
 pkg syscall (darwin-386-cgo), type Radvisory_t struct
 pkg syscall (darwin-386-cgo), type Radvisory_t struct, Count int32
 pkg syscall (darwin-386-cgo), type Radvisory_t struct, Offset int64
+pkg syscall (darwin-386-cgo), type RawSockaddr struct, Data [14]int8
 pkg syscall (darwin-386-cgo), type RawSockaddr struct, Family uint8
 pkg syscall (darwin-386-cgo), type RawSockaddr struct, Len uint8
 pkg syscall (darwin-386-cgo), type RawSockaddrAny struct, Pad [92]int8
@@ -11191,6 +11216,7 @@ pkg syscall (darwin-amd64), type Radvisory_t struct
 pkg syscall (darwin-amd64), type Radvisory_t struct, Count int32
 pkg syscall (darwin-amd64), type Radvisory_t struct, Offset int64
 pkg syscall (darwin-amd64), type Radvisory_t struct, Pad_cgo_0 [4]byte
+pkg syscall (darwin-amd64), type RawSockaddr struct, Data [14]int8
 pkg syscall (darwin-amd64), type RawSockaddr struct, Family uint8
 pkg syscall (darwin-amd64), type RawSockaddr struct, Len uint8
 pkg syscall (darwin-amd64), type RawSockaddrAny struct, Pad [92]int8
@@ -13016,6 +13042,7 @@ pkg syscall (darwin-amd64-cgo), type Radvisory_t struct
 pkg syscall (darwin-amd64-cgo), type Radvisory_t struct, Count int32
 pkg syscall (darwin-amd64-cgo), type Radvisory_t struct, Offset int64
 pkg syscall (darwin-amd64-cgo), type Radvisory_t struct, Pad_cgo_0 [4]byte
+pkg syscall (darwin-amd64-cgo), type RawSockaddr struct, Data [14]int8
 pkg syscall (darwin-amd64-cgo), type RawSockaddr struct, Family uint8
 pkg syscall (darwin-amd64-cgo), type RawSockaddr struct, Len uint8
 pkg syscall (darwin-amd64-cgo), type RawSockaddrAny struct, Pad [92]int8
@@ -14986,6 +15013,7 @@ pkg syscall (freebsd-386), type Msghdr struct, Iov *Iovec
 pkg syscall (freebsd-386), type Msghdr struct, Iovlen int32
 pkg syscall (freebsd-386), type Msghdr struct, Name *byte
 pkg syscall (freebsd-386), type Msghdr struct, Namelen uint32
+pkg syscall (freebsd-386), type RawSockaddr struct, Data [14]int8
 pkg syscall (freebsd-386), type RawSockaddr struct, Family uint8
 pkg syscall (freebsd-386), type RawSockaddr struct, Len uint8
 pkg syscall (freebsd-386), type RawSockaddrAny struct, Pad [92]int8
@@ -16961,6 +16989,7 @@ pkg syscall (freebsd-amd64), type Msghdr struct, Name *byte
 pkg syscall (freebsd-amd64), type Msghdr struct, Namelen uint32
 pkg syscall (freebsd-amd64), type Msghdr struct, Pad_cgo_0 [4]byte
 pkg syscall (freebsd-amd64), type Msghdr struct, Pad_cgo_1 [4]byte
+pkg syscall (freebsd-amd64), type RawSockaddr struct, Data [14]int8
 pkg syscall (freebsd-amd64), type RawSockaddr struct, Family uint8
 pkg syscall (freebsd-amd64), type RawSockaddr struct, Len uint8
 pkg syscall (freebsd-amd64), type RawSockaddrAny struct, Pad [92]int8
@@ -19081,6 +19110,7 @@ pkg syscall (linux-386), type PtraceRegs struct, Xes int32
 pkg syscall (linux-386), type PtraceRegs struct, Xfs int32
 pkg syscall (linux-386), type PtraceRegs struct, Xgs int32
 pkg syscall (linux-386), type PtraceRegs struct, Xss int32
+pkg syscall (linux-386), type RawSockaddr struct, Data [14]int8
 pkg syscall (linux-386), type RawSockaddr struct, Family uint16
 pkg syscall (linux-386), type RawSockaddrAny struct, Pad [96]int8
 pkg syscall (linux-386), type RawSockaddrInet4 struct, Family uint16
@@ -21266,6 +21296,7 @@ pkg syscall (linux-386-cgo), type PtraceRegs struct, Xes int32
 pkg syscall (linux-386-cgo), type PtraceRegs struct, Xfs int32
 pkg syscall (linux-386-cgo), type PtraceRegs struct, Xgs int32
 pkg syscall (linux-386-cgo), type PtraceRegs struct, Xss int32
+pkg syscall (linux-386-cgo), type RawSockaddr struct, Data [14]int8
 pkg syscall (linux-386-cgo), type RawSockaddr struct, Family uint16
 pkg syscall (linux-386-cgo), type RawSockaddrAny struct, Pad [96]int8
 pkg syscall (linux-386-cgo), type RawSockaddrInet4 struct, Family uint16
@@ -23429,6 +23460,7 @@ pkg syscall (linux-amd64), type PtraceRegs struct, Rip uint64
 pkg syscall (linux-amd64), type PtraceRegs struct, Rsi uint64
 pkg syscall (linux-amd64), type PtraceRegs struct, Rsp uint64
 pkg syscall (linux-amd64), type PtraceRegs struct, Ss uint64
+pkg syscall (linux-amd64), type RawSockaddr struct, Data [14]int8
 pkg syscall (linux-amd64), type RawSockaddr struct, Family uint16
 pkg syscall (linux-amd64), type RawSockaddrAny struct, Pad [96]int8
 pkg syscall (linux-amd64), type RawSockaddrInet4 struct, Family uint16
@@ -25596,6 +25628,7 @@ pkg syscall (linux-amd64-cgo), type PtraceRegs struct, Rip uint64
 pkg syscall (linux-amd64-cgo), type PtraceRegs struct, Rsi uint64
 pkg syscall (linux-amd64-cgo), type PtraceRegs struct, Rsp uint64
 pkg syscall (linux-amd64-cgo), type PtraceRegs struct, Ss uint64
+pkg syscall (linux-amd64-cgo), type RawSockaddr struct, Data [14]int8
 pkg syscall (linux-amd64-cgo), type RawSockaddr struct, Family uint16
 pkg syscall (linux-amd64-cgo), type RawSockaddrAny struct, Pad [96]int8
 pkg syscall (linux-amd64-cgo), type RawSockaddrInet4 struct, Family uint16
@@ -25809,6 +25842,2197 @@ pkg syscall (linux-amd64-cgo), type WaitStatus uint32
 pkg syscall (linux-amd64-cgo), var Stderr int
 pkg syscall (linux-amd64-cgo), var Stdin int
 pkg syscall (linux-amd64-cgo), var Stdout int
+pkg syscall (linux-arm), const AF_ALG ideal-int
+... (大量のLinux/ARM固有の定数、関数、型定義の追加) ...
+pkg syscall (linux-arm), type RawSockaddr struct, Data [14]uint8
+pkg syscall (linux-arm), type RawSockaddr struct, Family uint16
+pkg syscall (linux-arm), type RawSockaddrAny struct, Pad [96]int8
+... (さらに大量のLinux/ARM固有の定数、関数、型定義の追加) ...

src/cmd/api/goapi.go の変更は非常に小さく、go1.txt の更新をサポートするための内部的な調整と考えられます。

--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -10,6 +10,7 @@
 	"go/token"
 	"io/ioutil"
 	"log"
+	"runtime"
 	"sort"
 	"strings"
 )

コアとなるコードの解説

api/go1.txt の変更

api/go1.txt はGo 1 APIの公式な定義ファイルであり、このファイルへの変更はGo言語の互換性保証に直接影響します。このコミットでは、主に以下の2種類の変更が行われています。

  1. pkg log/syslog (linux-arm) の追加: log/syslog パッケージは、システムログデーモン(syslog)へのメッセージ送信機能を提供します。このコミットにより、Linux/ARM環境においても log/syslog パッケージの全ての公開API(定数、関数、メソッド、型)がGo 1 APIとして正式にサポートされることが明記されました。これは、GoがARMベースのLinuxシステム(例えばRaspberry Piなど)でより広範に利用されるための基盤を固めるものです。

  2. pkg syscall (linux-arm) の追加と RawSockaddr の型定義: これがこのコミットの最も重要な変更点です。syscall パッケージはOSのシステムコールを直接扱うため、OSやアーキテクチャに強く依存します。このコミットにより、Linux/ARM環境における syscall パッケージの膨大な数の定数(AF_ALG, ETH_P_IP, SYS_READ など)、関数(Accept, Open, Read など)、および型定義が go1.txt に追加されました。

    特に注目すべきは、pkg syscall (linux-arm), type RawSockaddr struct, Data [14]uint8 という行です。これは、Linux/ARMアーキテクチャにおいて、syscall.RawSockaddr 構造体の Data フィールドが [14]uint8 型であることを明示的に宣言しています。コミットメッセージにもあるように、他の多くのプラットフォームではこのフィールドは [14]int8 と定義されています。この差異を go1.txt に記載することで、Go 1 APIの互換性保証の範囲内で、Linux/ARMにおけるこの特定の型定義が公式に認められ、将来にわたって変更されないことが保証されます。

    この変更は、Goのクロスコンパイルや、異なるアーキテクチャ間で syscall パッケージを利用する際の挙動の予測可能性を高める上で重要です。開発者は go1.txt を参照することで、特定のプラットフォームにおけるAPIの正確なシグネチャを把握し、それに応じたコードを書くことができます。

src/cmd/api/goapi.go の変更

src/cmd/api/goapi.go は、GoのAPI定義を管理するための内部ツールです。このファイルへの変更は、go1.txt の内容を生成または検証するロジックに影響を与えます。

このコミットにおける goapi.go の変更は、import "runtime" の追加のみです。これは、goapi ツールがGoのAPIを分析する際に、runtime パッケージの情報(例えば、現在のOSやアーキテクチャに関する情報)を利用する必要が生じたことを示唆しています。具体的には、Linux/ARMのような新しいアーキテクチャのAPI定義を go1.txt に追加する際、goapi ツールがそのアーキテクチャ固有のビルドタグや環境情報を正しく認識し、適切なAPIセットを抽出・検証できるようにするために runtime パッケージが利用されたと考えられます。この変更自体はAPIの機能に直接影響を与えるものではなく、API定義の管理ツール側の改善です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコードリポジトリ
  • LinuxカーネルのCヘッダーファイル(sys/socket.h など)の一般的な定義
  • Go言語の syscall パッケージの内部実装に関する一般的な知識