クロスバージョン ランタイム保証
Protobuf 言語バインディングには 2 つのコンポーネントがあります。生成されたコード (gencode) と、その生成されたコードの共通機能を実装するランタイムライブラリです。これらが異なる Protobuf リリースから提供される場合、「クロスバージョンランタイム」の状況になります。
ほとんどの言語で以下の保証を提供することを意図しています。これらはデフォルトの保証ですが、Protobuf コードジェネレーターおよびランタイムの所有者は、その言語に対するより具体的な保証でこれらを明示的に上書きすることができます。C++ および Rust は一般的よりも厳しい保証を持ち、Python は緩い保証を持ちます。
保証外の Protobuf クロスバージョン使用は、エラーを起こしやすく、サポートされていません。バージョンスキューは、ソース互換性のない方法で何も変更されていない限り、動作しているように見えても、診断が困難なフリーズや未定義の動作を引き起こす可能性があります。Protobuf の場合、サポートされていない Protobuf 言語バインディングの使用に依存するツールやサービスの普及は、Protobuf チームがバグ報告やセキュリティ脆弱性に対応して Protobuf 実装を更新することを妨げます。
新しいGencode + 古いRuntime = 常に許可されない
私たちは、あらゆる種類のリリース (メジャー、マイナー、またはパッチ) で新しいランタイム API を追加する可能性があります。そのリリースの gencode は、これらの新しい API を使用することが許可されています。その結果、gencode は、バインディングを生成するために使用された protoc およびプラグインよりも古いランタイムとペアにすることはできません。
新しい gencode と古いランタイムをペアにしようとする試みを防ぐために、可能な限り「ポイズンピル」を追加します。
メジャーバージョン
Protobuf は、メジャーバージョンに対してスライディングウィンドウ互換性を実装しています。メジャーバージョン V (完全バージョン: V.x.y) 用に生成されたコードは、メジャーバージョン V および V+1 の Protobuf ランタイムによってサポートされます。
Protobuf は、バージョン V の gencode をランタイム >= V+2 と使用することをサポートしません。ソフトウェアアセンブリがこのような構成を使用しようとすると、明確なエラーメッセージで失敗する「ポイズンピル」メカニズムを使用します。
例
- Protobuf バージョン 3.0.0 で生成された Java コードは、ランタイム 3.0.0 から 4.x.y まで動作しますが、ランタイム 2.0.0 から 2.x.y またはランタイム >= 5.0.0 とは動作しません。
- Protobuf バージョン 4.27.2 で生成された Java コードは、ランタイム 4.27.2 から 5.x.y まで動作しますが、ランタイム 2.0.0 から 4.27.1 またはランタイム >= 6.0.0 とは動作しません。
セキュリティ修正のように、古い gencode との互換性を維持することができない場合、例外が設けられることがあります。
注意: ポイズンピルは Protobuf 26.0 リリースで導入されました。4.26.0 より古い Java gencode は、gencode よりも古いランタイムと動作するように見えるかもしれません。しかし、新しい gencode と古いランタイムの組み合わせは、ランタイム時まで顕在化しない深刻なバグを抱えている可能性があります。
注意: C++ および Rust は互換性ウィンドウをサポートせず、Python ははるかに長いものをサポートします。
マイナーバージョン
単一のメジャーランタイムバージョン内で、古いバージョンの protoc から生成されたコードは、新しいランタイムで実行されます。
注意: C++ および Rust は、マイナーバージョン間での互換性をサポートしません。
セキュリティ例外
セキュリティ上の理由で必要と判断された場合、上記の約束を破る権利を留保します。これらの例外はまれであると予想されますが、常にこれらの保証よりもセキュリティを優先します。例えば、footmitten CVE は、Java のランタイムと生成されたコードの両方に対するペア更新を必要としました。その結果、3.20.3 (footmitten の修正が含まれる) で生成されたコードは、ランタイムライブラリ 3.21.6 (footmitten の修正よりも古い) ではロードされず、以下の互換性マトリックスが作成されました。
| 生成コードバージョン | |||||
| 3.20.2 | 3.20.3 | 3.21.6 | 3.21.7 | ||
| ランタイム バージョン | 3.20.2 | 脆弱性あり | !破損! | !脆弱性あり! | !破損! |
| 3.20.3 | 脆弱性あり | 動作する | !脆弱性あり! | !動作する?! | |
| 3.21.6 | 脆弱性あり | 破損 | 脆弱性あり | !破損! | |
| 3.21.7 | 脆弱性あり | 動作する | 脆弱性あり | 動作する | |
- 「脆弱性あり」は、その組み合わせが正常に起動するが、セキュリティ脆弱性が依然として存在することを示します。
- 「動作する」は、その組み合わせが正常に起動し、脆弱性がないことを示します。
- 「破損」は、その組み合わせが正常に起動しないことを示します。
- !太字!は、新しい gencode と古いランタイムを組み合わせた、決して一緒に動作するよう意図されていない構成を示します。
複数メジャーランタイムバージョンの非共存
同じプロセスにおける複数のメジャーバージョンの共存はサポートされていません。
C++ および Rust 固有の保証
Protobuf C++ および Rust は、すべてのクロスランタイムサポートを放棄し、常に生成されたコードバージョンとランタイムバージョンの厳密な一致を要求します。
さらに、Protobuf C++ は、いかなるリリース (メジャー、マイナー、マイクロ) においても ABI 安定性に関する保証を一切行いません。
Python 固有の保証
3.20.0 リリース以降、Protobuf Python の生成コードは、埋め込み FileDescriptorProto の薄いラッパーになりました。これらのプロトは非常に長い期間サポートされているため、通常、私たちの標準的なメジャーバージョン互換性ウィンドウは必要ありません。
Python は、将来の特定のメジャーバージョンリリースで生成コードの互換性を破る可能性がありますが、事前にポイズンピルの警告とエラーが伴います。6.32.0 時点では、3.20.0 以降に生成されたすべてのコードは、少なくとも 8.x.y までサポートされます。