G14 — CPython Limited-API / abi3 import-contract conformance¶
Registry: UC-WF-stable-abi-subset (planned)
Effort: M · Risk: low
Problem¶
Every abi3 wheel promises it uses only the stable CPython C-API subset, so
one binary runs on all Py_LIMITED_API-compatible interpreters. abicheck has
the substrate to verify this (the ELF/PE/Mach-O undefined-symbol table, plus
the appcompat engine) but no driver that checks it. Today compare/appcompat
reason about a binary's exports; for an extension module the exports are
essentially just PyInit_<mod> — the compatibility surface that actually
matters is what the module imports from libpython.
Empirically confirmed (cryptography 42.0.8 → 43.0.3, both cp39-abi3):
abicheck comparereturnsCOMPATIBLE— judged entirely from the export table (1 → 25 exported symbols).- The real contract is invisible: the module's imported CPython symbols grow
from 111 → 118
Py*(e.g.PyByteArray_AsString/Size/Type,PyNumber_And/Multiply/Power,PyObject_GenericSetDict,Py_DecRef/IncRef). If any imported symbol were outside theabi3set, or newer than the wheel's declaredPy_LIMITED_APIfloor, the wheel would fail to import on an older interpreter with anundefined symbolerror — and abicheck would still sayCOMPATIBLE.
Goal & acceptance criteria¶
- [ ] A check that enumerates an extension's imported CPython C-API symbols
and classifies each against a stable-ABI allowlist for a target
Py_LIMITED_APIversion. - [ ] An imported symbol outside the
abi3set (or newer than the declared floor) is reported as a deployment-RISK/BREAKINGfinding that reaches the verdict and JSON/SARIF — not silentlyCOMPATIBLE. - [ ] A clean
abi3extension passes; a--no-limited-apiextension that imports a non-stable symbol is flagged.
Design¶
- Capture undefined/imported symbols already available in the snapshot substrate; expose an imported-symbol view on the model if not present.
- Ship a stable-ABI allowlist (the
abi3symbol set per CPython minor; sourced from CPython'sDoc/data/stable_abi.dat, vendored as data, refreshable). - A driver
abicheck stable-abi <ext.so> [--abi3 3.9]classifies imports; wires through the existing reporter and a newRISK/BREAKINGChangeKind(added per the rootCLAUDE.mdfour-step procedure). - Cross-platform: the same idea applies to
python3.dll(PE imports) and the macOS.sotwo-level-namespace imports.
Files & surfaces¶
abicheck/model.py(imported-symbol view if missing), a newabicheck/stable_abi.py+ vendored allowlist data, a CLI moduleabicheck/cli_stable_abi.py(registered per the rootCLAUDE.md"Adding a new top-level command"),abicheck/checker_policy.py(new kind), reuse ofabicheck/reporter.py.
Tests¶
- Unit: a synthetic extension importing only
abi3symbols → pass; one importing a non-stable_Py*/version-newer symbol → flagged. - An example pair under
examples/withground_truth.jsonentry.
Out of scope¶
Verifying a wheel's declared tag against its contents end-to-end (packaging concern); non-CPython stable ABIs.