跨版本运行时保证
Protobuf 语言绑定包含两个组件:生成的代码(通常由 protoc
生成)和使用生成的代码时必须包含的运行时库。当这两者来自 Protobuf 的不同版本时,我们就处于“跨版本运行时”的情况。
我们打算为大多数语言提供以下保证。这些是默认保证;然而,Protobuf 代码生成器和运行时的所有者可以用该语言更具体的保证来明确覆盖它们。C++ 和 Rust 的保证比通常更严格,而 Python 的保证则更宽松。
超出保证范围的 Protobuf 跨版本使用是容易出错且不受支持的。版本偏差可能导致难以诊断的*不稳定和未定义行为*,即使在源不兼容方面没有任何变化时,它也常常*看起来*可以正常工作。对于 Protobuf 来说,依赖于使用不受支持的 Protobuf 语言绑定的工具和服务不断增多,这阻碍了 Protobuf 团队为应对错误报告或安全漏洞而更新 Protobuf 实现。
新生成的代码 + 旧的运行时 = 绝不允许
我们可能会在任何类型的版本(主版本、次版本或补丁版本)中添加新的运行时 API。该版本中生成的代码可以使用这些新的 API。其结果是,生成的代码不应与比用于生成这些绑定的 protoc
和插件更早的运行时配对。
我们将尽可能添加“毒丸”(poison pills),以防止将较新生成的代码与较旧的运行时配对的尝试。
主版本
从 2025 年第一季度发布的版本开始,Protobuf 项目将为主版本采用滚动兼容性窗口。为主版本 V(完整版本号:V.x.y)生成的代码将受到 V 和 V+1 版本的 Protobuf 运行时的支持。
在此政策之前,为 3.22.x+(主版本 4 发布前约 1 年的版本)生成的代码仍将受到版本 3 和 4 的 Protobuf 运行时的支持。使用较旧生成代码的用户应升级到 3.25.x 的最新生成代码。
Protobuf 将不支持使用版本 V 生成的代码与版本 >= V+2 的运行时,并将使用“毒丸”机制,在软件组件尝试使用此类配置时以明确的错误消息失败。
注意: C++ 和 Rust 不支持兼容性窗口,而 Python 支持更长的兼容性窗口。
次版本
在单个主运行时版本内,由旧版 protoc
生成的代码可以在新版运行时上运行。
注意: C++ 和 Rust 不支持跨次版本的兼容性。
安全例外
如果出于安全原因需要,我们保留违反上述承诺的权利。我们预计这些例外情况会很少见,但将始终优先考虑安全性而非这些保证。例如,footmitten 漏洞要求对 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 | 有漏洞 | 正常 | 有漏洞 | 正常 |
- “有漏洞”表示该组合可以成功启动,但安全漏洞仍然存在。
- “正常”表示该组合可以成功启动并且没有该漏洞。
- “损坏”表示该组合无法成功启动。
- 粗体表示根据本主题中概述的保证,从未有意让这些配置协同工作。
不支持多个主运行时版本共存
不支持在同一进程中并存多个主版本。
C++ 和 Rust 的特定保证
Protobuf C++ 和 Rust 不提供任何跨运行时支持,并要求生成的代码版本和运行时版本在任何时候都完全匹配。
此外,Protobuf C++ 不对任何版本(主版本、次版本或微版本)的 ABI 稳定性做出任何保证。
Python 的特定保证
自 3.20.0 版本以来,Protobuf Python 生成的代码变成了一个围绕嵌入式 FileDescriptorProto
的薄封装。由于这些 proto 在极长的时间范围内得到支持,我们通常的主版本兼容性窗口通常不是必需的。
Python 可能会在未来的特定主版本中破坏生成的代码的兼容性,但会提前通过毒丸警告和错误来提示。截至 6.32.0,自 3.20.0 以来生成的所有代码将至少支持到 8.x.y 版本。