首页
/ CPython 3.19 C API 废弃解读:PEP 456 字符串哈希方案定制支持(Embedder Support)的移除

CPython 3.19 C API 废弃解读:PEP 456 字符串哈希方案定制支持(Embedder Support)的移除

2026-09-06 13:35:55作者:卓炯娓

本篇技术解读基于 CPython 仓库中的废弃公告文件 c-api-pending-removal-in-3.19.rst。该文档宣布:在 Python 3.19 中,将移除「PEP 456 为嵌入方(embedder)提供的字符串哈希方案定义支持」。读完后你将理解 PEP 456 曾向 C 嵌入层暴露了哪些哈希定制接口、这些接口在 CPython 源码中的具体落点,以及嵌入式集成方(自定义 Python 宿主应用、C 扩展构建系统)在 3.19 到来前应如何完成迁移。

一、公告本身:一行声明背后的含义

CPython 仓库在 Doc/deprecations/ 目录下维护了一批按目标版本归类的 C API 废弃追踪文档。其中 c-api-pending-removal-in-3.19.rst 的完整内容只有一条条目:

Pending removal in Python 3.19
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* :pep:`456` embedders support for the string hashing scheme definition.

这条声明的技术含义是:PEP 456 当年除了改变解释器内部的字符串哈希实现,还额外开放了一组「让嵌入方在编译期定义字符串哈希方案」的 C 宏与 API。这一组面向 embedder 的定制能力(而非 PEP 456 的哈希随机化本身)将要在 3.19 中被删除。

二、背景:PEP 456 的 embedder 接口在 CPython 中的落点

PEP 456(随 Python 3.4 引入)把 Python 字符串的哈希从固定的 DJBX33A 变体更换为抗碰撞攻击的 SipHash 系列算法,并引入哈希随机化。与此同时,它向嵌入层开放了三个定制维度,全部集中在公开头文件 pyhash.h 中:

2.1 算法选择:Py_HASH_ALGORITHM 与四个取值

pyhash.h 中定义了可选算法枚举及默认值选择逻辑:

#define Py_HASH_EXTERNAL 0
#define Py_HASH_SIPHASH24 1
#define Py_HASH_FNV 2
#define Py_HASH_SIPHASH13 3

#ifndef Py_HASH_ALGORITHM
#  ifndef HAVE_ALIGNED_REQUIRED
#    define Py_HASH_ALGORITHM Py_HASH_SIPHASH13
#  else
#    define Py_HASH_ALGORITHM Py_HASH_FNV
#  endif
#endif
  • 默认情况下,支持对齐内存访问的平台使用 SipHash13,不支持的平台回退到 FNV;
  • 头文件注释明确指出「The values for Py_HASH_* are hard-coded in the configure script」,即算法值由构建配置固化;
  • 嵌入方此前可以通过在编译定义中强制 Py_HASH_ALGORITHM(例如设为 Py_HASH_EXTERNAL)来接管字符串哈希的计算。

2.2 短字符串优化阈值:Py_HASH_CUTOFF

pyhash.h 还定义了短字符串快速哈希的截断长度:

/* Cutoff for small string DJBX33A optimization in range [1, cutoff).
 *
 * About 50% of the strings in a typical Python application are smaller than
 * 6 to 7 chars. However DJBX33A is vulnerable to hash collision attacks.
 * NEVER use DJBX33A for long strings!
 */
#ifndef Py_HASH_CUTOFF
#  define Py_HASH_CUTOFF 0
#elif (Py_HASH_CUTOFF > 7 || Py_HASH_CUTOFF < 0)
#  error Py_HASH_CUTOFF must in range 0...7.
#endif

取值被硬约束在 0..7 区间(0 表示禁用短字符串优化),越界会在编译期直接报错。注释同时说明了安全权衡:短字符串用快速的 DJBX33A、长字符串用 SipHash,以在典型负载(约一半字符串长度小于 6~7 字符)与抗碰撞攻击之间取得平衡。

2.3 外部哈希实现注入:PyHash_FuncDef

真正属于「embedders support for the string hashing scheme definition」的核心 API 位于 cpython/pyhash.h(该头文件仅在不定义 Py_LIMITED_API 时经 pyhash.h 间接包含):

/* hash function definition */
typedef struct {
    Py_hash_t (*const hash)(const void *, Py_ssize_t);
    const char *name;
    const int hash_bits;
    const int seed_bits;
} PyHash_FuncDef;

PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void);

PyHash_FuncDef 描述了当前字符串哈希函数指针、算法名称以及哈希位宽/种子位宽;PyHash_GetFuncDef() 允许嵌入方在运行时查询这些元信息。pyhash.h 的注释还给出了外部注入方式——当 Py_HASH_ALGORITHMPy_HASH_EXTERNAL 时,嵌入方可提供:

PyHash_FuncDef PyHash_Func = {...};

这一声明路径在实现层有直接对应:pyhash.c 开头即有 #if Py_HASH_ALGORITHM == Py_HASH_EXTERNAL 分支,外部模式下哈希计算委托给嵌入方提供的实现,而 SipHash13/SipHash24/FNV 各实现则分别位于该文件后续的条件编译块中。

2.4 运行时可观测性:sys.hash_info

哈希方案的当前状态还通过 C API 暴露到解释器运行时。例如 sysmodule.c 在构建 sys.hash_info 时会写入 cutoff 值(SET_HASH_INFO_ITEM(PyLong_FromLong(Py_HASH_CUTOFF)))。从源码结构看,一旦 embedder 定制接口移除,sys.hash_info 中将只反映内置算法的状态,不再存在由外部注入的算法名。

三、3.19 之后:嵌入方还能做什么

需要澄清一个关键边界:被移除的只是「方案定义/替换」能力,而非哈希随机化本身。字符串哈希仍由 CPython 内置算法计算,哈希值在不同进程间的随机性继续由 PYTHONHASHSEED 环境变量控制(该机制在官方参考文档 datamodel.rst 中有专门章节说明)。对嵌入集成方而言,迁移要点如下:

  1. 清理构建定义:从 C 编译参数中移除对 Py_HASH_ALGORITHMPy_HASH_CUTOFF 的自定义覆盖。这两个宏在 3.19 中不再有「由嵌入方定义方案」的语义价值;
  2. 移除外部哈希实现:删除自实现的 PyHash_Func 变量、PyHash_FuncDef 结构填充代码,以及任何依赖 PyHash_GetFuncDef() 返回值的 hash_bits/seed_bits 字段做分支适配的逻辑;
  3. 替代策略
    • 若当初选择 Py_HASH_EXTERNAL 是为了跨进程/跨版本保证哈希值稳定,改用固定 PYTHONHASHSEED 即可获得等价的确定性;
    • 若当初是出于性能原因替换为更快(但可碰撞)的算法,3.19 后该权衡不再开放给嵌入方,需接受内置算法的性能特征;
  4. 注意稳定 ABI 面PyHash_FuncDef/PyHash_GetFuncDef 属于非有限 API(需包含完整 CPython 头文件且未定义 Py_LIMITED_API 才可见),Limited API 使用方本就不应依赖,无需迁移。

四、版本边界与仓库现状

截至当前仓库快照,pyhash.hcpython/pyhash.h 中的上述宏和 API 仍然完整存在,pyhash.c 也仍保留 Py_HASH_EXTERNAL 分支。这与废弃公告的「Pending removal in Python 3.19」措辞一致:这些接口在 3.19 之前的版本中仍可用(且未标注 deprecation 警告),到 3.19 才会被移除。嵌入方在针对 3.19 及以后版本编译时,应假定这些符号不存在。

五、参考路径索引

内容 路径
废弃公告(本文主体) Doc/deprecations/c-api-pending-removal-in-3.19.rst
算法选择与 cutoff 宏 Include/pyhash.h
PyHash_FuncDef / PyHash_GetFuncDef Include/cpython/pyhash.h
哈希算法实现与 EXTERNAL 分支 Python/pyhash.c
sys.hash_info 构建 Python/sysmodule.c
PYTHONHASHSEED 说明 Doc/reference/datamodel.rst
登录后查看全文
热门项目推荐
相关项目推荐