microsoft/bocpy v0.7.0
microsoft/bocpy
Captured source
source ↗0.7.0 - SBOM and Dependency Auditing
Repository: microsoft/bocpy
Tag: v0.7.0
Published: 2026-06-02T11:11:47Z
Prerelease: no
Release notes: Cown-lifecycle correctness fixes — three use-after-free paths in the `CownCapsule pickle / acquire / noticeboard machinery now hold the inner BOCCown` alive across the writer's wrapper drop — plus supply-chain hardening: pinned and hash-verified Python dependencies, SHA-pinned GitHub Actions, dependabot coverage, vulnerability scanning, and PEP 770 SBOMs embedded in every wheel.
New Features
- PEP 770 SBOMs in every wheel — every wheel built by
.github/workflows/build_wheels.yml now embeds a CycloneDX 1.6 _ JSON SBOM under -.dist-info/sboms/bocpy.cdx.json. Generation runs inside cibuildwheel's repair step on every platform (Linux auditwheel, macOS delocate, Windows direct injection) via the new stdlib-only scripts/build_sbom.py. The inject subcommand rewrites the wheel's RECORD` atomically (temp file + rename).
- SBOM verification in CI — the new `
verify_sboms` job in
build_wheels.yml re-downloads the extracted SBOM artifact and runs two checks: scripts/validate_sbom.py (stdlib-only structural validator pinning bocpy's wire format) and grype _ (third-party SBOM scanner) with --fail-on high. A separate sboms artifact is also uploaded by the merge` job for downstream consumers.
- ``bocpy.__version__`` — a runtime version attribute derived
from `importlib.metadata.version("bocpy"), with a PackageNotFoundError fallback. Exported from bocpy.__all__ and documented in __init__.pyi. pyproject.toml` remains the single source of truth for the version.
- New documentation — :doc:
sbomwalk-through covering the
embedded SBOM format, extraction recipes, and verification commands.
- ``wait(noticeboard=True)`` final-state capture — :func:
wait
now accepts a `noticeboard keyword that returns the final noticeboard contents as a plain dict at shutdown (after the noticeboard thread exits, before the entries are freed). Useful for surfacing an early-stopping result, last error, or aggregated counter that a behavior deposited just before the runtime quiesced, replacing the older send / receive handshake that earlier examples used. Combined with stats=True it returns a new :class:WaitResult NamedTuple (also exported from bocpy.__all__) carrying both snapshots. The examples/prime_factor.py` example was migrated to the new pattern.
Bug Fixes
- Cown-in-cown use-after-free — a `
Cown` embedded inside
another cown's value, a message-queue payload, or a noticeboard snapshot was previously freed when the writer's local wrapper dropped, because pickle bytes carry no refcount on their own. `CownCapsule_reduce now takes an inheriting COWN_INCREF that _cown_capsule_from_pointer_inheriting consumes on unpickle, so the inner BOCCown survives until the consumer drops its decoded wrapper. Affects every cross-cown reference shape — see the new TestCownInCown` class for the full container-shape fuzz.
- Acquire-failure poisoned-state — when `
pickle.loads` failed
partway through `cown_acquire, the cown was left in a half-acquired state with the encoded bytes still in place. A retry would re-run pickle against bytes whose embedded inherited refs had already been partially consumed by pickle's error path, risking dereferences of freed BOCCown* pointers. The cown's xidata is now recycled on the failure path and a guard at the top of cown_acquire rejects any future acquire with a deterministic RuntimeError`; the worker recovery arm surfaces it on the failing behavior's result cown.
- Noticeboard hidden-cown audit — when a noticeboard value
reached a `Cown via a route the pin walker cannot see — custom __reduce__ / __getstate__, copyreg.dispatch_table, closure capture, module-level cache — the borrowing reconstructor produced a token whose inner BOCCown was not held alive by the entry's pin set, leaving the next reader to UAF after the writer's wrapper dropped. A per-thread borrowing context (BOC_NB_CTX) now audits every CownCapsule_reduce against the caller's pin set during the noticeboard write pickle and fails the whole notice_write / notice_update` closed if any cown is unaccounted for.
- `UnicodeDecodeError` on non-UTF-8 Windows locales —
Behaviors.start read worker.py with open(path), which picks up locale.getpreferredencoding(False). On cp1252 (English Windows) the UTF-8 em-dashes in the worker source were silently mojibake-d; on cp949 (Korean Windows) the read failed with UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 and bocpy could not start at all (reported in #14 _ by @Forthoney _). Fixed by passing encoding="utf-8" explicitly in Behaviors.start, and the same fix was applied to every other open() site in the repo that reads or writes text known to contain non-ASCII bytes (sphinx/source/conf.py, examples/sketches.py x2, export_module.py`).
- Silent worker-startup failures — `
Behaviors.start_workers
ran `interpreters.create() and interpreters.run_string() on the worker thread without a try/except, so a failure in either killed the thread without ever replying on boc_behavior. The parent's bounded receive() then timed out with no diagnostic. Both calls are now wrapped, and every failure path sends a formatted traceback over boc_behavior` so the parent sees a structured error instead of a timeout.
- Silent worker bootstrap import failures — the generated
bootstrap script that loads the user module into each worker sub-interpreter is now wrapped in a top-level try/except. Any `BaseException is formatted with the user module name and sent over boc_behavior (falls back to sys.stderr if the message-queue send itself raises), then re-raised so run_string` reports it as well. Module-import failures that previously surfaced only as a worker-startup timeout now arrive as a proper traceback.
- ``boc_sched_worker_pop_slow`` skipped ``popped_local`` — the
slow-path pending-fallback and WSQ-dequeue branches returned work without bumping `popped_local (the fast path always did), so the documented producer/consumer identity in :c:type:boc_sched_stats_t` was violated whenever the fairness arm fired or a worker entered the slow path directly.…
Excerpt shown — open the source for the full document.
Notability
notability 3.0/10Routine library release, low traction