Skip to content

fix(python): refuse copy=False over memory no Python object owns - #170

Merged
brndnmtthws merged 1 commit into
mainfrom
fix/borrowed-ownerless-memoryview
Oct 20, 2026
Merged

brndnmtthws merged 1 commit into
mainfrom
fix/borrowed-ownerless-memoryview

Conversation

@brndnmtthws

Copy link
Copy Markdown
Owner

What

DMatrix(x, copy=False) refuses an array whose base chain reaches a memory view without an exporter (obj is None), such as ctypes.memoryview_at(...) or a C extension's PyMemoryView_FromMemory.

A view like that doesn't own its memory and keeps nothing alive that does. #169's read_only_chain treated it as the buffer's owner, and #169's review fix (3380d8fe) let it through when it was read-only. A matrix could then borrow memory that might be freed under it. Keeping _array alive, and its weak-reference pins, keeps an allocation alive only when some Python object owns it. That's what BorrowedArray's SAFETY argument relies on.

Changes

  • python/src/borrowed.rs: read_only_chain returns an error for an ownerless memory view instead of asking that view's buffer whether it is read-only; the module and function docs list the refusal.
  • python/python/hessboost/_matrix.py: DMatrix's Raises: names it.
  • python/tests/test_data.py: on Python >= 3.14, an array from np.frombuffer(ctypes.memoryview_at(addr, size, readonly=True)) is refused, and the same values in bytes are borrowed. The ctypes buffer that owns the memory stays alive for the whole test, so nothing reads freed memory. The test failed before the fix ("DID NOT RAISE") and passes after. It skips on 3.12 and 3.13, which have no memoryview_at.

Checks (local)

  • python/: cargo fmt --check, cargo clippy --all-targets -- -D warnings, the same with --features cuda, uv run --locked pytest (449 passed), pyright --verifytypes hessboost --ignoreexternal (100%)
  • root: ruff check, ruff format --check, ty check

A memory view without an exporter (`obj` is `None`: `ctypes.memoryview_at`,
or a C extension's `PyMemoryView_FromMemory`) does not own its memory and
keeps nothing alive that does, so `read_only_chain`, which took such a
view for the buffer's owner, let a matrix borrow memory that could be
freed under it: keeping the array and the view alive keeps the allocation
alive only when some object owns it. `DMatrix(copy=False)` now refuses an
array whose base chain reaches an ownerless memory view; Python >= 3.14
tests it with `ctypes.memoryview_at(..., readonly=True)` over a ctypes
buffer that outlives the test.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T21:25:03.643194Z 00328b4 PR opened
🔒 Security Review ✅ Completed 2026-10-20T21:25:22.397577Z 00328b4 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@brndnmtthws
brndnmtthws merged commit 2183fbd into main Oct 20, 2026
38 checks passed
@brndnmtthws
brndnmtthws deleted the fix/borrowed-ownerless-memoryview branch October 20, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant